开发者

How should I inspect the object graph created by a factory in a unit test

I have some code similar to the following:

public interface IMyClass
{
    MyEnum Value { get; }
    IMyItemCollection Items { get; }
}

public class MyConcreteClassFactory : MyClassFactoryBase
{
    public override IMyClass Create(MyEnum value)
    {
        var itemBuilder = new MyRemoteItemBuilder();
        var itemCollection = new MyLazyItemCollection(itemBuilder)

        return new MyClass(value, itemCollection);
    }
}

The 'real' code should only care about the fact that the factory returns an instance of IMyClass - not what the concrete implementation is. Still, I would like to test that the factory class does what it is supposed to - build a concrete object graph.

Should I write some tests that call the create method and inspect the properties of the returned object? This question seems to indicate so, but does that still apply if I need to inspect several layers of classes and properties to verify the object graph created by the factory? Wouldn't that lead to test code such as:

var created = objectUnderTest.Create(MyEnum.A);
var itemBuilder = (created.Items as MyLazyItemCollection).Builder;
Assert.IsInstanceOfType(itemBuilder, typeof(MyRemoteItemBuilder));

I'm not particularly fond of the downcast of created.Items, but as I see it that would be the only way to assert that the factory created the MyLazyItemCollection correctly, since not every IMyItemCollection can be expected to have a builder property... And this is only the second layer of the graph. I might need to dig even further into the dependencies of the MyRemoteItemBuilder to see if they were created correctly:

var service = ((created.Items as MyLazyItemCollection)
   .Builder as MyRemoteItemBuilder).Service;
Assert.IsInstanceOfType(service, typeof(MyService)开发者_如何学编程);

Should I test my factory in this manner, accepting the unsightly nested downcasts - this is test code, after all - or should I pull the IMyItemCollection construction into another factory and add this as a dependency to my MyConcreteClassFactory (so I could inject it from the test code and assert that the value of created.Items was the instance created by my mocked factory). I expect the latter would quickly lead to an explosion in factory-factories and factory-factory-factories. After all, the user of the MyConcreteClassFactory shouldn't need to be bothered with the fact that she has to supply specific sub factories, should she..?


It is of cause depends on needs, but my answer is NO.

You should never design your tests in a manner "Test implementation (or detail)", that might work really nice at the beginning, but after a while you will be in trouble. Implementation is chaning really fast, with each change you are forced to correct many test cases.

In opposite, you must "Test behaviour". It basically means you abstract of all details (concrete class) and you tests cases testing some valuable scenarios, instead of details.

My options is to create "Test implementation" cases, then I'm doind TDD. But later on they have to be refactored out with "Test behaviour" cases.

This is quite important if you case not only about count of test case, but quality in building real Safety Net.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜