While writing unit tests for a module I ran across a few challenges... Given a module like:
package Module::Under::Test; sub method1 { ... $self->method2( ... ); ... } To properly unit test this I want to replace method2 with a mock method so that I am only testing the actions of method1. The question is, how do you inject an overridden method2, aside from subclassing Module::Under::Test, which introduces other concerns (see below). What I'd ideally like to do is take an instantiated Module::Under::Test object, and dynamically remap that instance to point to a different method2. Something like: my $mut = Module::Under::Test->new(); $mut->method2 = sub { ... }; which of course wouldn't work. A typeglob could be used here: *Module::Under::Test::method2 = sub { ... }; but that alters the class, rather than the instance, and could impact other methods in the unit test. (I suppose one could save the current value and restore it later.) My understanding is that Perl's OO dereferencing for methods doesn't involve the object instance, other than to obtain the class name so it can find the right package namespace. If this is correct, then there probably isn't a way to do this other than subclassing. This kind of thing is easy to do in JavaScript: var mut = new Module.Under.Test(); mut.method2 = function () { ... }; but in JavaScript there aren't real classes - everything is an instance. Still, it'd be a shame to think JavaScript could do something Perl can't. :-) Another issue is how to simulate a "private" package namespace. For example, lets say you go the subclass route mentioned above, and in your test class create a test method like: sub test_method1 { ... { package My::Module::Under::Test; use base qw(Module::Under::Test); sub method2 { ... } } my $mut = My::Module::Under::Test->new(); ... } While you can declare a package in this fashion, the My::Module::Under::Test package has global visibility. To minimize the possibility of conflicts with other similar subclasses declared in other test methods, you'd ideally want to do something like: package __PACKAGE__::__SUB__::Module::Under::Test; But this doesn't work. As documented, __PACKAGE__ doesn't get interpolated. It has to be by itself. __SUB__, although I found references to it on Usenet, doesn't seem to actually exist. The easy solution here is to perform the substitution manually as you write the code, but it'd be nice if there was a more automated approach. It seems the only option is to do a string eval like: my $PACKAGE = __PACKAGE__; eval "package ${PACKAGE}::Module::Under::Test;" . q{ use base qw(Module::Under::Test); sub method2 { ... } }; (Similarly caller() could be used to provide the equivalent of what the hypothetical __SUB__ would have provided.) Which works, but being a string eval this carries the down side of deferring syntax checking until run time, which is less than ideal. Maybe this would work: { eval "package " . __PACKAGE__ . "::Module::Under::Test;"; use base qw(Module::Under::Test); sub method2 { ... } } but I haven't tried it. I would expect not, as method2 will get added to the symbol table at compile time before the package namespace gets set. So does anyone know of hacks for dynamically generating a package namespace string? Is there any way to create an anonymous class? (Which is apparently possible in Java.) Given that everything has to end up in the global symbol table, I'm guessing not. Will any of this stuff be addressed in Perl 6? -Tom -- Tom Metro Venture Logic, Newton, MA, USA "Enterprise solutions through open source." Professional Profile: http://tmetro.venturelogic.com/ _______________________________________________ Boston-pm mailing list Boston-pm@mail.pm.org http://mail.pm.org/mailman/listinfo/boston-pm