Testing the untestable with Test::MockFile

Todd Rinaldo described one of the problems with testing cPanel's software. Unlike the projects most of us work on, cPanel is more a system administration tool. This means that it does more OS-level work than most people are used to.

He began with a reference to the book How Google Tests Software He followed that up with an example of how you might mock opendir. He also showed another module that was close to what they needed: Overload::FileCheck.

Eventually, they createdd Test::MockFile This module uses filehandles tied on the mocked file. In the process of working on the module, they found that tie is not as well-documented as one might hope. It turned out that mocking files was pretty easy, but directories were harder.

When mocking low-level Perl functionality, there are two namespaces you should be aware of: CORE and CORE::GLOBAL. It turns out that you cannot override methods in the CORE namespace, but you can override the equivalent in CORE::GLOBAL. Also, because of the nature of these methods, you must do the redefinition in a BEGIN block. You must also take into account the prototype when doing the redefinition.

As an example,

open( my $fh, '>', 'foo' );

BEGIN {
    *CORE::GLOBL::open (*;$@) = sub {
        die;
    }
}

open( my $fh, '>', 'bar' );

exit;

If you want to transfer control to the old routine without a new stackframe, remember to use goto \&CORE::open; (naming the old method). Interestingly, this did not work in Perl 5.14 or older. The only choice was to call the old routine.

The hardest part of this exercise was dealing with edge cases.

Alternative Approaches

Todd also suggested a few alternative approaches, that might work in some situations.

Other Suggestions

Todd recommended Devel::Trace to understanding how Perl is seeing your code. He also recommended Test::Spec for a declarative style of test writing.

We had 8 people attending this month. As always, we'd like to thank cPanel, L.L.C. for providing the meeting space and food for the group.