Having just got back from an awesome break in Thailand and Taiwan, I just updated my object pooling utility. Thanks to Ostra Ceruzka for raising an issue with its strict mode functionality with me – all fixed now! Serves me right for not writing enough tests, huh?
Since I’m not sure whether I have indeed invented a new design pattern here. So, alternative titles for this post include:
- Dependency Injection without a Dependency Injection framework
- Why misuse of the default namespace for tests is pure evil
- How to make your code more testable without completely messing it up
You need to use some kind of Dependency Injection (DI for short) to provision some System Under Test (SUT for short) in tests you’re writing, but can’t or don’t want to use a DI framework to do so.
Of course, the simplest form of DI is simply passing things to a constructor. But you probably don’t want to code every class to be handed every dependency at construction. And you definitely don’t want to expose the private parts of your implementation through some unnecessary interface. No, you really don’t!
I’ve seen scary examples of what I call ‘keyhole surgery’ on classes, either by abuse of the internal namespace to allow poking into otherwise private implementation, or just by making too many things public. Although the internal namespace (AKA the default namespace) is perceived to retain a sufficient level of encapsulation, it really doesn’t. Anything in the same package can jump all over it, so it’s somewhat of a loose interface. As such, you should never leave methods unscoped, letting them default to the internal namespace. You should also reserve the internal namespace only for when you are in control of all classes that will exist in the same package, such as when creating utility classes.
Loose interfaces are bad practice for a few reasons:
- Clarity – anyone using the class will be confused as to the intentions of its interface
- Stability – a class with such a loose interface is open to misuse and a recipe for failure
- Cleanliness – code for tests does not belong in your production code
- Testability – you should test a class through its interface, not its implementation
- Flexibility – it is hard to refactor classes that leak implementation detail in such a way
Well, this is one possible solution and ultimately just my suggestion. It’s especially useful when needing to refactor classes with overuse of the internal namespace, since you won’t need to change much test or production code. I call it the Dependency Injection by Extension pattern.
How it works:
You provide DI helpers as protected methods in your SUT and subclass it from within your test case, as a script-level class, to expose the DI helpers as public and/or use the constructor to do some of the DI work – allowing you to inject mocked dependencies for your tests. This has the advantage of not allowing anything else to meddle with your SUT, other than through its interface, of course. And, if anything in your production code wishes to extend your SUT, potentially overriding and messing up the interface, then that class should have its own tests anyway.
The following example shows a very basic class (SystemUnderTest) being extended from within its testcase (SomeTest) to allow injection and access to its dependencies, for the purpose of verifying its behaviour under given conditions.
protected var someDependency : Dependency;
private var _someThing : Thing;
public function SystemUnderTest()
someDependency = new Dependency();
_someThing = new Thing();
public function doSomething() : void
_someThing.callSomething( someDependency.getSomething() );
protected function get someThing() : Thing
public class SomeTest
private var sut : SystemUnderTestWithDI;
private var someThing : Thing;
private var mockDependency : Dependency;
public function setUp()
mockDependency = mock(Dependency);
sut = new SystemUnderTestWithDI(mockDependency);
someThing = sut._someThing;
public function testSomething():void
var testValue : String = ‘foo’;
given( mockDependency.getSomething() ).willReturn( testValue );
verify().that( someThing.callSomething( eq(testValue) ) );
class SystemUnderTestWithDI extends SystemUnderTest
public function SystemUnderTestWithDI(dependency : Dependency)
someDependency = dependency;
public function get _someThing() : Thing