【问题标题】:TDD How to Assert that a property of a POCO is set within a method that is being testedTDD 如何断言在正在测试的方法中设置了 POCO 的属性
【发布时间】:2014-07-09 15:54:49
【问题描述】:

我们正在使用 TDD 和 DI 方法以及 NSubstitute 创建一个 C# 应用程序。

我们正在编写一个CreateThing 方法:

  • namedescription 字符串作为参数
  • 创建一个新的Thing 对象
  • 从方法参数中设置ThingNameDescription属性
  • Status 设置为Active
  • Thing 传递给另一个类的方法(通过构造函数注入)以进行进一步处理

我们知道如何使用Substitute.For.Received() 编写对另一个类的调用的测试。

我们如何为正在设置的Thing 属性编写测试?

【问题讨论】:

  • nsubstitute.github.io/help/received-calls section "检查对属性的调用"
  • 通话前后断言
  • @WiktorZychla - Thing 在方法内部实例化,因此在测试中不可访问
  • 如果是这样,那么您在创建具体实例时没有遵循 DI,而不是注入它以便注入模拟。
  • 但是 Thing 是一个 POCO,我们的 create 方法接受创建 POCO 所需的值...为什么/如何注入这个?

标签: c# dependency-injection tdd nsubstitute


【解决方案1】:

您可以使用Argument matchers 即条件匹配器,它看起来像Arg.Is<T>(Predicate<T> condition)。您的匹配器可能如下所示:

anotherClass.Received().Process(Arg.Is<Thing>(thing => !string.IsNullOrEmpty(thing.Name)));

完整列表:

public class Thing
{
    public string Name { get; set; }
}

public class AnotherClass
{
    public virtual void Process(Thing thing)
    {
    }
}

public class CreateThingFactory
{
    private readonly AnotherClass _anotherClass;

    public CreateThingFactory(AnotherClass anotherClass)
    {
        _anotherClass = anotherClass;
    }

    public void CreateThing()
    {
        var thing = new Thing();
        thing.Name = "Name";
        _anotherClass.Process(thing);
    }
}

public class CreateThingFactoryTests
{
    [Fact]
    public void CreateThingTest()
    {
        // arrange
        var anotherClass = Substitute.For<AnotherClass>();
        var sut = new CreateThingFactory(anotherClass);

        // act
        sut.CreateThing();

        // assert
        anotherClass.Received().Process(Arg.Is<Thing>(thing => !string.IsNullOrEmpty(thing.Name)));
    }
}

【讨论】:

  • 感谢您的回答。我确实知道那个解决方案,但是,现在测试不是在测试两件事吗? 1) 另一个类被调用并且 2) 它是用设置了 Name 的参数调用的。我读过/看到/听说过的关于 TDD 的所有内容都表明这是一个很大的禁忌……测试应该只测试一个“规则”。
  • @Shevek,据我所知,Alexandr 的回答符合您的要求。如果您担心这是测试太多,那么也许考虑更改您的设计以将创建逻辑与协调创建和传递“进一步处理”的责任分开。这可能意味着一个新类处理Thing 创建和测试它返回一个带有所需属性集的Thing。然后,您可以测试您的原始类正确地将创建逻辑的结果传递给“进一步处理”类。由您决定是否觉得增加的复杂性是有帮助还是有阻碍。
  • @Shevek 我同意大卫的观点。如果您遵循 TDD,那么您首先编写测试,并且不会遇到当前情况询问如何测试。还有一件事,没有严格的规则可以在一次测试中只断言一件事。在测试中做任何你认为合乎逻辑和方便的事情。许多断言类似事情的测试很难维护。
  • 感谢你们的cmets
猜你喜欢
  • 2021-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-07
  • 2016-11-09
  • 2011-04-19
相关资源
最近更新 更多