Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling

How to use a private version of a published module?

by MARKWIN (Novice)
on Jun 18, 2021 at 14:57 UTC ( #11134006=perlquestion: print w/replies, xml ) Need Help??

MARKWIN has asked for the wisdom of the Perl Monks concerning the following question:

So I am trying to publish a module that allows access to IG's API directly. This would allow simple listings of your spread bet positions. The module is written and works well for me. Under the hatch it uses the CPAN module Rest::Client for formatting requests.

In order to test it it needs to be able to be tested without the use of my personal IG login details as these are private to me. The test programs use the unmodified module, with a special @INC path from which it picks up a special version of Rest::Client. This version hashes the parameters, and then reads a file based on the hash and returns identical json formatted data as if my account had been used.

My aim is to test my module, not Rest::Client which is not my module.

I included the special version of Rest::Client and in my module code as well as a Record::Rest::Client for creating the special data files read by my local Rest::Client module.

All works well, however when I submit the module, it says I have no permission to publish a version of Rest::Client. I do not actually want to do that, its only used in the testing of my module.

I seek some suggestions as to what is the best way to proceed in this situation.

  • Comment on How to use a private version of a published module?

Replies are listed 'Best First'.
Re: How to use a private version of a published module?
by hippo (Bishop) on Jun 18, 2021 at 15:23 UTC
      I had not come accross this module before. It looks good, but doesn't solve the ultimate problem as far as I can see.

      My test code does not call Rest::Client, which is what I need to mock. Rest::Client is used by the module under test, not the test code.

      To test the module under test I do not expect to change it!

      I tweak the INC path so that when the module under test loads Rest::Client it gets my mock version.

      I already have a very good mock, one that does exactly what I need and works well. I want the innocent and unchanged use line in the module under test to load the same-named mock module rather than the real one.

      The problem I have is that I cannot include the mock module in my module due to a name space violation, after all I did not write Rest::Client so I cannot publish it, even as a sub module.

      How can I publish this module without violating the real owners name space? Is there a way to include a module as source code without exporting that module?

        My test code does not call Rest::Client, which is what I need to mock. Rest::Client is used by the module under test, not the test code.

        It does not matter where in the chain of calls REST::Client is used. It is the subs within REST::Client which are mocked. You do not need to change your module at all. Your test script sets up the mocking, instantiates an object of your class and when your test script calls some method of your class which, somewhere down the line, calls a method on REST::Client, that is what is magically mocked by Test::MockModule.

        Trust me on this, mocking is definitely the way to go here. You don't have to use Test::MockModule - there are plenty of other good mocking modules. The very fact that there are many of them should hopefully indicate to you how prevalent mocking is as a valid test tool and to get around precisely the problem you are presently having.


Re: How to use a private version of a published module?
by stevieb (Canon) on Jun 18, 2021 at 18:22 UTC

    Here's an example of mocking any subroutine in any module at any level of depth (using my Mock::Sub distribution).

    Order of operation: <- <- <- REST::Client

    So is our module we're testing with, can be someone else module used by our, and REST::Client is being used by the module which we have no control over.

    package A; use lib '.'; use B; sub new { return bless {}, shift; } sub call_b { my ($self) = @_; my $b = B->new; return $b->call_rest_client; } 1;

    package B; use REST::Client; sub new { return bless {}, shift; } sub call_rest_client { my ($self) = @_; my $client = REST::Client->new; $client->GET('adfdsaf'); return $client->responseContent; } 1;

    use warnings; use strict; use feature 'say'; use lib '.'; use A; use Mock::Sub; my $obj = A->new; say "Before mocking REST::Client->responseContent:\n"; say $obj->call_b; # Mock the sub, and set a custom return value my $response_client_sub = Mock::Sub->new->mock('REST::Client::response +Content'); $response_client_sub->return_value('{"a": 1, "b": 2}'); say "After mocking REST::Client->responseContent:\n"; say $obj->call_b;


    Before mocking REST::Client->responseContent: Can't connect to adfdsaf:80 (Name or service not known) Name or service not known at /home/spek/perl5/perlbrew/perls/perl-5.26 +.1/lib/site_perl/5.26.1/LWP/Protocol/ line 50. After mocking REST::Client->responseContent: {"a": 1, "b": 2}

    See the documentation for Mock::Sub for full details and usages.

Re: How to use a private version of a published module?
by Anonymous Monk on Jun 19, 2021 at 17:59 UTC

    Where is your mocked module in your distribution? I typically put them in inc/mock/ and then have the toolchain tell PAUSE not to index inc/. Last I heard the Makefile.PL way to do this is to add the following to the data you pass to WriteMakeFile():

    META_ADD => { no_index => [ qw{ inc } ], },

    My notes say this requires Module::Build version 6.4501 or higher.

    The mechanism for Build.PL is similar.

      Thank you, thats useful.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11134006]
Approved by LanX
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2022-05-20 20:58 GMT
Find Nodes?
    Voting Booth?
    Do you prefer to work remotely?

    Results (76 votes). Check out past polls.