[Pdx-pm] interesting testing hole thats been dug

Michael G Schwern schwern at gmail.com
Wed Jan 3 02:36:57 PST 2007


benh wrote:
> A co-worker and I are wondering how/what the best way around this is?
> 
> we have a module that cans up all our DB connections... but when I
> want to test it should be a mocDB object... so we now have a DBTest
> that builds out the mocDB stuffies. But the issue now is that to get
> all the existing scripts to use DBTest for our tests.
> 
> Is there a clean way to intercept DB calls? is there some kinda bubble
> that we can toss the scripts in to and then any call out gets
> redirected? Our inital though was to just set an env var and then when
> the script would run then it would pick the right object, but that
> requires selecting a use statement (ie if($ENV{test}){use DBTest; }
> else {use DBHost;} ) alas that doesn't work.... any other ideas?

If you're putting testing code into production code something is wrong.  Your production code should not have any special cases for testing.  Its a red flag stating that your code is inflexible.  That elements of its configuration and class structure are hard coded.  If its hard to test, chances are it'll be hard to use.

There's several ways to handle this.

The first, and least elegant, is to have your tests replace methods of your database class so that they are mocked up.

    use DBHost;

    no warnings 'redefine';
    *DBHost::connect = sub {
        ...mock code here...
    };

While this avoids having to put special cases into your code, it doesn't do anything to increase the flexibility of your code.


A better option is to put the decision as to which DB class to use into some configuration option.  Then your tests can just change the config.


Another is instead of your system loading the database class and instanciating a new database object, the database object it should use can be passed into the system.  This allows the calling code, your test, to compose the elements of the system rather than they be hard coded.


Finally, you can question why you're mocking the database connection at all.  As its not testing the real code, mocking should be a last resort.  (I presume by mocking you mean replacing the database methods with dummy calls that return dummy data).  Instead, consider having the tests create a new test database, load some test data in it and work from that.  SQLite is fantastic for this sort of thing.


More information about the Pdx-pm-list mailing list