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

Hello,

I'm using Test::Class to organize and run my test suite. I've not found a way to pass data between modules (which are subclasses)

Service.pm - Base test class
package Service; use base qw/ Test::Class /; use Test::More; sub common_method : Test(1) { my $self = shift; ok (1 == 1, 'common_method'); } 1;
Service_A.pm - Specific to Service A
package Service_A; use base qw/ Service /; use Test::More; sub method_of_a : Test(1) { my $self = shift; ok (1 == 1, 'method_of_a'); } 1;
Service_B.pm - Specific to Service B
package Service_B; use base qw/ Service /; use Test::More; sub method_of_b : Test(1) { my $self = shift; ok (1 == 1, 'method_of_b'); } 1;
run.t - test script
#!/usr/bin/perl use strict; use warnings; use Service_A; use Service_B; Test::Class->runtests();

A good unit testing framework would imply that I test each module independently. But in this particular case, the input for Service_B needs the output of the tests from Service_A. To clarify, I'm running this against a sandbox, and I cannot access Service_B without first initializing and using relevant data from Service_A.

I tried the obvious, i.e. define a foo() accessor in the base Service class, and then use set/get in Service_A/Service_B respectively, but this does not work.

I also tried all possible ways of running the tests as shown in the RUNNING TESTS section of the Test::Class manual.

One way which would work is to write a new module which uses both these services in the same file, but that would involve a lot of cut and paste, and definitely my last resort. The other would be to use some sort of temporary store - like a file or maybe even shared memory.

I was wondering if any of you have come across this problem, and found a way out, preferably using Test::Class and if not, what is the best way to solve this.

Many Thanks.

Update

Problem solved! By using a class variable in the base Service module. This is now accessible from all class instances.


--
Rohan

Replies are listed 'Best First'.
Re: Passing data between modules using Test::Class
by adrianh (Chancellor) on Dec 12, 2006 at 18:19 UTC
    I tried the obvious, i.e. define a foo() accessor in the base Service class, and then use set/get in Service_A/Service_B respectively, but this does not work.

    The reason being that Service_A and Service_B tests would be run on different objects that don't share state.

    I was wondering if any of you have come across this problem, and found a way out, preferably using Test::Class and if not, what is the best way to solve this.

    Without more information on the relationship between the service objects it's hard to tell. Can you show what/why Service_B needs Service_A's test results?

      Hey Adrian,

      As I mentioned in my updated post, I'm now passing data by use of a class variable common to both Service_A and Service_B

      Without more information on the relationship between the service objects it's hard to tell. Can you show what/why Service_B needs Service_A's test results?

      I don't think that should matter. This test suite is for the Google::Adwords module. When I run the sandbox tests for, say the CampaignService test module, I then require the campaign ids for use in the AdGroupService test module. These are only for the sandbox tests, and I can test the various service modules independently otherwise.


      --
      Rohan

        I don't think that should matter. This test suite is for the Google::Adwords module. When I run the sandbox tests for, say the CampaignService test module, I then require the campaign ids for use in the AdGroupService test module. These are only for the sandbox tests, and I can test the various service modules independently otherwise.

        Fair enough. If it were me I'd probably factor out the common code into a separate module that both test classes used, enabling me to run each class independently. But that's just me ;-)

Re: Passing data between modules using Test::Class
by pemungkah (Priest) on Dec 13, 2006 at 20:27 UTC
    I'd be much more tempted to use a mock object for A when testing B. The mock object does nothing except provide the output you want for B.

    Why is this useful? If you're only testing B with good output from A, what happens when B gets bad input? You haven't tested that if you're dependent on the real A providing data; you've only tested the "got good data" paths. Depending on the complexity of A's output and B's processing, this could leave a lot of code untested.

    Since this has to do with actual money (and possible losses thereof) I'd want to make sure I had tested all the code paths.

      I don't really care if module B gets bad input from module A, as that is most likely taken care of as a generic input error. But I do care about the correct values returned after I invoke Service A, which I then need to send to Service B. Service B can only be invoked after I get some values from Service A.

      Mocking Service A sounds like a good idea, and I may look further into this, provided the sandbox returns the same results everytime


      --
      Rohan