Opalescent Dependencies
There are two modes when working on objects having what Scott Bellware calls “Transparent Dependencies.” Check it out right now. In Design/TDD Mode you will want to mock up the dependencies and feed them into the constructor of the class under test, like so (using Rhino Mocks here):
private MockRepository _mocks = new MockRepository(); [Test] public void CreditCheckService_ShouldDenyCreditToCustomersWithLessThan600PointScore { ICreditCheckServiceAgent mockAgent = _mocks.CreateMock<ICreditCheckServiceAgent>(); PocoCustomerEntity stubCustomer = _mocks.Stub<PocoCustomerEntity>(); using (_mocks.Record()) { SetupResult.For(stubCustomer.ID).PropertyBehavior().Return(42); Expect.Call(mockAgent.ObtainScore(42)).Return(599); LastCall.IgnoreArguments(); } using (_mocks.Playback() { CreditCheckService theUnit = new CreditCheckService(mockAgent); Assert.IsFalse(theUnit.GrantCustomerCredit(stubCustomer)); } }
In this wee code fragment we see our unit (class under test, system under test, etc.) is the CreditCheckService. It takes, as a dependency in its constructor, a ICreditCheckServiceAgent interface who is responsible for calling out to an outside service. Imagine a DunsCreditCheckServiceAgent implementation.
Sidebar: note the name of the test method. I like to name my test methods with long names that typically begin with “Should”. That sentence should express some behavior of the unit and be understandable by a business folks and developers alike.
So, again, Scott does a fine job of describing the benefit of the fundamental approach of lifting your dependencies in to the constructor so that mocks can be fed in for testing purposes. This is the bread and butter of TDD. Imagine, though, in a realistic scenario you have a class with loads and loads of dependencies. What then Mr. TDD? Doesn’t my Consumer Coding Mode (our second mode) become cumbersome and tedious to write? Dependency Injection containers to the rescue! Using a DI/IoC container the syntax of the consumer code stays very clean:
CreditCheckService service = IoC.Resolve<CreditCheckService>();
The idea here is that the Inversion of Control container will build up or resolve the object for you based on some configuration. It’s been told that when it finds a constructor parameter of this type or that or a setter property of a certain type to go ahead, create or resolve that type and shove in the dependency. You get two main benefits here: one the dependency resolution rules are (potentially) external to the binary and your code remains concise, terse. It should be mentioned that I’m using in my IoC example Ayende’s IoC-service-locator thing which I think is pretty slick. I’ll also point you to Aaron and Jacob’s rather cool AutoMocking container thing as a short-hand way of saying DI can help out in “test mode” too.
Post a Comment