我应该如何在单元测试中检查工厂创建的对象图

时间:2011-07-14 07:34:24

标签: c# unit-testing tdd

我有一些类似于以下内容的代码:

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);
    }
}

'真正的'代码应该只关心工厂返回IMyClass实例的事实 - 而不是具体实现。不过,我想测试一下工厂类是做了它应该做的 - 构建一个具体的对象图。

我应该编写一些调用create方法并检查返回对象属性的测试吗? This question似乎表明了这一点,但如果我需要检查几层类和属性来验证工厂创建的对象图,那么它仍然适用吗?这不会导致测试代码,如:

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

我并不是特别喜欢created.Items的垂头丧气,但我认为这是断言工厂正确创建MyLazyItemCollection的唯一方法,因为不是每一个IMyItemCollection可以预期有一个构建器属性......而这只是图的第二层。我可能需要进一步深入研究MyRemoteItemBuilder的依赖关系,看看它们是否被正确创建:

var service = ((created.Items as MyLazyItemCollection)
   .Builder as MyRemoteItemBuilder).Service;
Assert.IsInstanceOfType(service, typeof(MyService));

我应该以这种方式测试我的工厂,接受难看的嵌套向下转换 - 毕竟这是测试代码 - 或者我应该将IMyItemCollection构造拉到另一个工厂并将其作为依赖项添加到我的{{ 1}}(所以我可以从测试代码中注入它并断言MyConcreteClassFactory的值是我的模拟工厂创建的实例)。我预计后者会很快导致工厂和工厂工厂爆炸。毕竟,created.Items的用户不应该为她必须提供特定的子工厂而烦恼,如果她......?

1 个答案:

答案 0 :(得分:1)

这取决于需要,但我的答案是否定的。

你绝不应该以“测试实现(或细节)”的方式设计你的测试,这可能在开始时非常好用,但过了一段时间你就会遇到麻烦。实现非常快,每次更改都会被迫纠正许多测试用例。

相反,你必须“测试行为”。它基本上意味着您抽象所有细节(具体类),并测试测试一些有价值的场景而不是细节的案例。

我的选择是创建“测试实现”案例,然后我就是TDD。但是后来他们必须用“测试行为”案例进行重构。

如果您不仅要考虑测试案例的数量,而且要建立真正的安全网的质量,这一点非常重要。