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

标签 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 实例的事实——而不是具体实现是什么。尽管如此,我还是想测试一下工厂类是否做了它应该做的事情——构建一个具体的对象图。

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

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

我不是特别喜欢 created.Items 的沮丧,但在我看来,这是断言工厂创建了 MyLazyItemCollection 的唯一方法正确,因为并非每个 IMyItemCollection 都可以预期具有 builder 属性......这只是图表的第二层。我可能需要进一步深入了解 MyRemoteItemBuilder 的依赖关系,看看它们是否已正确创建:

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

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

最佳答案

当然要看需求,但我的回答是否定的。

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

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

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

如果您不仅要论证测试用例的数量,还要论证构建真实安全网的质量,这一点非常重要。

关于c# - 我应该如何检查工厂在单元测试中创建的对象图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6689884/

相关文章:

通过子类化 TestCase 进行 Python 参数化单元测试

c# - 查询的技术和模式?

c# - 将 XML 解析为对象数组 - 使用 Silverlight/Windows Phone

android - 如何在 Espresso 中测试布局的 UI,而不将其附加到 Activity?

unit-testing - Gulp Mocha 和 Browserify 的绝对路径

ruby - RSpec:模拟、 stub 和验证

node.js mocha 测试请求

javascript - 如何使用 ...spread 获取作为函数参数的函数的 "returns"?

c# - 如何从 asp.net 处理程序返回 404 错误?

c# - 系统.Runtime.Serialization.InvalidDataContractException : No set method for property