Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Re^7: Introspecting function signatures (Dependency Injection and Monkey Patching)

by eyepopslikeamosquito (Archbishop)
on Mar 07, 2021 at 07:02 UTC ( [id://11129243]=note: print w/replies, xml ) Need Help??


in reply to Re^6: Introspecting function signatures
in thread Introspecting function signatures

"dependency injection" is how this is called in the case of pytest, maybe it is not a generic term

Well, I think Dependency Injection is a very well-known generic term, and heavily used in statically typed languages (e.g. C++, Java, C#) though it seems to be much less popular in dynamic languages, such as Perl and Python, as indicated here:

Dependency injection (DI) is regarded with suspicion in the Python world ... The standard way to do things is to declare our dependency implicitly by simply importing it, and then if we ever need to change it for tests, we can monkeypatch, as is Right and True in dynamic languages.
A reply to this SO question states that "A MonkeyPatch is a piece of Python code which extends or modifies other code at runtime (typically at startup)".

In frustration, I searched all of docs.pytest.org and the only reference I found to dependency injection was:

consider using pytest’s more powerful fixture mechanism which leverages the concept of dependency injection
So please put me out of my misery by pointing us at the pytest dependency injection documentation you saw.

BTW, I've happily used Dependency Injection for years in C++ (but not Perl). In C++, you define an interface argument to the class constructor, then, in the unit test, inject a mock object (an instance of a class inheriting from the interface class), while injecting an instance of the real class (also inheriting from the same interface class) in production code. ... Hmmmm, I see I liked it so much that I explicitly singled it out as "perhaps the most important design pattern in making code easier to test" at Effective Automated Testing.

Update: See this reply for a nice example of using Dependency Injection in Perl by chromatic.

Monkey Patching References

  • Comment on Re^7: Introspecting function signatures (Dependency Injection and Monkey Patching)

Replies are listed 'Best First'.
Re^8: Introspecting function signatures
by LanX (Saint) on Mar 07, 2021 at 12:52 UTC
    I think this niche is mainly filled by conditional use/imports in dynamic languages (see if )

    Monkey patching is only one other possibility here (that's replacing a sub/method at runtime), we also have eval and BEGIN blocks ... etc.

    > In frustration, I searched all

    that's "terminology injection" (aka die "brain overflow" ;-)

    Like all these Java OO "design patterns" which are superfluous in Perl.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

      that's "terminology injection" (aka die "brain overflow" ;-)
      Ha ha, I noticed a mind-boggling number of different ways to do this type of stuff in Perl. For example, chromatic refers here to a modernperlbooks article which gives the illustrative example below:

      At its core, dependency injection is a formalization of the design principle "Don't hard-code your dependencies." Consider the code:

      sub fetch { my ($self, $uri) = @_; my $ua = LWP::UserAgent->new; my $resp = $ua->get( $uri ); ... }

      That's not bad code by any means, but it's a little too specific and a little less generic due to the presence of the literal string LWP::UserAgent. That might be fine for your application, but that hard-coding introduces a coupling that can work against other uses of this code. Imagine testing this code, for example. While you could use Test::MockObject to intercept calls to LWP::UserAgent's constructor, that approach manipulates Perl symbol tables to work around a hard coded dependency.

      An alternate approach uses a touch of indirection to allow for greater genericity:

      use Moose; has 'ua', is => 'ro', default => sub { LWP::UserAgent->new }; sub fetch { my ($self, $uri) = @_; my $ua = $self->ua; my $resp = $ua->get( $uri ); ... }
      Now the choice of user agent is up to the code which constructs this object. If it provides a ua to the constructor, fetch() will use that. Otherwise, the default behavior is to use LWP::UserAgent as before.

      Lots of stuff on CPAN too:

      As usual, the hard part is knowing which is good and which is crap. Please let us know of other cool CPAN offerings I've overlooked.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11129243]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (4)
As of 2024-12-02 19:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found