0

我有一个看起来像这样的测试:

    [Test]
    public void Blah()
    {
        // Arrange
        // ...
        var thing = new Thing();
        mockRouter.Route(Arg.Is<Transition<Thing>>(x => x != null && x.Subject != null && x.Subject.Equals(thing)));

        // Act
        var result = handler.Handle(thing);

        // Assert
        mockRouter.Received(1).Route(Arg.Is<Transition<Thing>>(x => x != null && x.Subject != null && x.Subject.Equals(thing)));
    }

我想将Arg定义缓存在局部变量中,以便可以在断言中重用它。关键是减少测试中的代码量并使其阅读起来更加流畅。

    [Test]
    public void Blah()
    {
        // Arrange
        var thing = new Thing();
        var transitionForThing = Arg.Is<Transition<Thing>>(x => x != null && x.Subject != null && x.Subject.Equals(thing));
        mockRouter.Route(transitionForThing);
        // ...

        // Act
        var result = handler.Handle(thing);

        // Assert
        mockRouter.Received(1).Route(transitionForThing);
    }

这似乎不起作用,因为 的值为transitionForThing空,因此断言失败,说Received(null)没有被调用。有没有办法做到这一点或类似的事情,还是我坚持这种语法?

4

2 回答 2

1

Arg.Is 有一个参数类型

Expression<Predicate<T>>

,因此您可以将其定义为重用

Expression<Predicate<Transition<Thing>>> predicate = 
  x => x != null && x.Subject != null && x.Subject.Equals(thing));

并将其用作

mockRouter.Route(predicate);

但我真的不明白你的情况:你通常模拟返回一些你需要的结果的类。我认为在你的情况下,你只需要检查模拟类的方法是否被调用,你不需要为动作定义一个模拟。

于 2014-08-27T13:56:46.880 回答
0

Arg.Is(...)和其他方法返回的值Arg相对不重要。重要的是方法本身的调用。

每次Arg.Is(...)调用 NSubstitute 都会记录您尝试指定一个参数,并使用该信息来计算您指定的调用的详细信息。如果您缓存该值(将只是default(T)),NSubstitute 将不知道您要匹配相同的参数。

如果您有兴趣,我可以对此进行更多解释,但需要注意的重要一点是,您Arg.Is(...)每次指定呼叫时都需要进行呼叫(并且按照呼叫预期的正确顺序)。

要重用匹配器逻辑,我会将谓词提取到一个新方法中(如DaniCE 建议的那样),或者创建一个调用Arg.Is并谨慎使用它的方法。

[Test]
public void Blah() {
    var thing = new Thing();
    mockRouter.Route(Arg.Is<Transition<Thing>>(x => HasSubject(x, thing)));
    // ...
    var result = handler.Handle(thing);
    // ...
    mockRouter.Received(1).Route(Arg.Is<Transition<Thing>>(x => HasSubject(x, thing)));
}

private bool HasSubject(Transition<Thing> x, Thing thing) {
    return x != null && x.Subject != null && x.Subject.Equals(thing));
}

//or...
[Test]
public void Blah2() {
    var thing = new Thing();
    mockRouter.Route(ArgWith(thing));
    // ...
    var result = handler.Handle(thing);
    // ...
    mockRouter.Received(1).Route(ArgWith(thing));
}

private Transition<Thing> ArgWith(Thing thing) {
    return Arg.Is<Transition<Thing>>(x => x != null && x.Subject != null && x.Subject.Equals(thing));
}
于 2014-08-28T12:02:01.990 回答