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

Dear Brothers and Sisters in Perl,

Recently I was adding some tests to a module I have written and I thought that in this particular instance it would be good if the module being tested was aware of it being tested, so it could slightly change its behaviour.

Is there an easy way to check if a module is run by a test script? I can of course write a semaphore file and check that, but that seems overkill, not to mention the overhead of checking for the file every-time.

CountZero

A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

  • Comment on How to make a module aware it is being tested?

Replies are listed 'Best First'.
Re: How to make a module aware it is being tested?
by dragonchild (Archbishop) on Nov 01, 2007 at 23:50 UTC
    In general, you use an environment variable for this kind of behavior. I would strongly urge against it because that kinda negates the point of being tested. It sounds like you have an XY problem. You probably want to use some sort of mock object instead of having the module provide the mocking.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
      As I explained above, the tests will remain the same, it is just the test-data to be inserted in the database that needs to be "manipulated" so they do not interfere with the real data. As the data are parsed out of external files I cannot change (since that would defeat the testing of the parsing routines) I thought it was a good idea to change some fields after the parsing but before the insertion. On second thought and as suggested elsewhere a testing database would solve all those problems nicely.

      CountZero

      A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: How to make a module aware it is being tested?
by GrandFather (Saint) on Nov 01, 2007 at 21:51 UTC

    Sprinkle if (exists $INC{'Test/More.pm'}) (or whatever test module you are using) tests through your code as required.

    That doesn't tell you if the code was actually called in a test context, but it does tell you if the test environment is loaded.


    Perl is environmentally friendly - it saves trees
      Seems like it would be a little more straightforward to test for one of the testing package's variables, like
      if ($Test::VERSION)

      Caution: Contents may have been coded under pressure.
Re: How to make a module aware it is being tested?
by gamache (Friar) on Nov 01, 2007 at 21:20 UTC
    It seems like a dubious idea at best to deliberately make a module act differently for a test, but if you're really dedicated to it, why not add a method or two, perhaps a $self->test getter and setter, followed by some internal logic (or whatever madness you got goin' on under the hood)? Then you call that method in your test scripts, and everything is fine.

    Then you could write a test to see if your test method is doing what you think it is.

      I agree with you that in general changing the behaviour of a module when it is being tested is not a good idea, but in this case I wish the module to add a distinguishing mark to the primary key field of a database record when it is being tested so the records inserted by the test cannot be mistaken for real records. The module will have to work with an active / life database and the records to be inserted are parsed from real life example files which I cannot change.

      Your idea of flagging to the module it is being tested is good, but it means I have to rewrite all my tests to add that flag and in the future may not forget to use that flag.

      CountZero

      A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

        The module will have to work with an active / life database and the records to be inserted are parsed from real life example files which I cannot change.
        Setting up a database for testing by copying a few records from the live database sounds like a better idea.
Re: How to make a module aware it is being tested?
by KurtSchwind (Chaplain) on Nov 02, 2007 at 00:27 UTC
    I'm sort of with others on this. I'd be reluctant to test for file existance, or some of those other things. I think it's better to set/get a test variable when you call it for test mode.

    It sounds like this isn't for public consumption (since you mentioned sticking test records in a database). If that's the case, then I'd definitely just have a test variable you can set for unit testing. This may cause you to write some wrapper subs that do the test and return strings based on whether the test was set.

    Also, I'd recommend some immediate output (to log or whatever you use) indicating that the module is acting in TEST mode. You really don't want to push that out to prod and end up with test crap in your database.
    --
    I used to drive a Heisenbergmobile, but everyone I looked at the speedometer, I got lost.
      You really don't want to push that out to prod and end up with test crap in your database.

      All too true, hence my initial idea to have the module check whether it was being tested or not. When in testing mode it would insert data records with a clearly identifiable "TEST" mark which would be easy to remove even if the test totally crashed and did not clean-up at the end.

      But I'm now convinced that a test database is probably the better choice.

      CountZero

      A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: How to make a module aware it is being tested?
by brian_d_foy (Abbot) on Nov 02, 2007 at 23:13 UTC

    What was theuse case that you had where this would be useful? This sound a bit like an XY Problem.

    Were you setting variables to different configuration values or something like that? Are you trying to mock a function? There's probably a much more robust way to accomplish your goal that doesn't involve magic or fragile code such as checking for a particular module. If you need to do this, the trick is to be able to control it yourself and not depend on something you can't control.

    A case I have is credit card processing. I have a program that can charge a credit card. In the `make test` step of development, I don't want to charge the card. However, in deploying it, I also want to do a human test without charging the card. One of these test situations is under the test harness framework, and one isn't.

    I use an environment variable. If I set the environment variable specifically tailored to my script (TEST_PROGRAM_NAME, for instance), which I can do in a program file or on the command line, my program can recognize the test condition with something I know that only I am affecting, I don't have to figure out acrobatics. Also, In my test harness stuff, I can turn the environment variable on and off, either in separate test scripts or even the same test script.

    However, I can also do that with a configuration directive. I turn off or on features I need in the normal pogram configuration. That way I can change how the program acts without the test scripts having to invoke a magic environment variable to change behavior.

    Another case I have is using the right database. In a test situation I have to hit a test database and in production I have to hit another. That's usually a matter of having the right configuration hooks. Inside the test situation though, often I want to test things that don't need the database, but at the semi-integration testing level I want to invoke the application, and the application wants to talk to the database. There I'll use some sort of Mock DBI object that pretends to connect to the database (and probably mocks returning the right data for particular calls). This is the same sort of thing I wold do if I needed my application to talk to the network, but I want to test it offline.

    I don't want to recommend anything in particular without knowing what you are trying to accomplish, though. As with all program design problem, the trick is to reduce special cases. :)

    And, finally, if your module acts differently under test conditions, how are you going to test how it acts not under test conditions? :)

    --
    brian d foy <brian@stonehenge.com>
    Subscribe to The Perl Review
      My use case is as follows:

      I get external files which I need to parse to extract the data I have to save into a database. I cannot change these external files as that would invalidate the testing of the whole parsing process.

      The next step is to save this data into the database, BUT

      • The database is live; and
      • the testing process might crash and fail to clean-up the data it inserted during testing.

      Hence my idea to change the primary keys of the data to be inserted, so

      • the other programs using the database recognize the data as test-data and will not use them; and
      • it is easy to manually delete the inserted test-data in case the test script crashed and failed to clean-up.

      For that to work I had thought it would be easiest if my module would "know" when it was being tested, so it could manipulate the test data as explained above. Rather than relying on environment variables, external semaphore files or additional attributes on the module's object (all of which a programmer might forget to set or provide), I was looking for a solution which could be built-in, but it seems there is no easy fool-proof automatic way to check if a module is being "tested".

      CountZero

      A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James