Moq方法调用序列比较

时间:2017-09-25 00:48:20

标签: c# unit-testing moq

在xUnit测试中,我想比较一个引用类和被测试类之间的方法调用(序列和值),它们调用一个模拟类。

例如:

public interface ITarget
{
    void A(string val);
    void B(int val);
}

public class RefClass
{
    private readonly ITarget m_target;
    public RefClass(ITarget target) { this.m_target = target; }
    public void Work()
    {
        this.m_target.A("A");
        this.m_target.A("B");
        this.m_target.B(0);
        this.m_target.B(1);
    }
}

public class TestClass
{
    private readonly ITarget m_target;
    public TestClass(ITarget target) { this.m_target = target; }
    public void Work()
    {
        this.m_target.A("B");
        this.m_target.B(1);
        this.m_target.B(0);
        this.m_target.A("A");
    }
}

public class WorkTest
{
    [Fact]
    public void Work_is_done_in_sequence()
    {
        var refTarget = new Mock<ITarget>();
        var refClass = new RefClass(refTarget.Object);
        refClass.Work();

        var testTarget = new Mock<ITarget>();
        var testClass = new TestClass(testTarget.Object);
        testClass.Work();

        //TODO : compare refTarget and testTarget method call sequence
    }
}

如何比较测试类使用目标接口的方式与引用类完全相同?感谢。

2 个答案:

答案 0 :(得分:0)

  

如何比较测试类使用目标接口   与引用类完全相同的方式?

通过设置模拟的相同预期行为并在执行测试方法后验证它们。

您甚至可以设置一个模拟并在目标类中重用它。然后,您可以验证两次执行相同的预期行为。

[Fact]
public void Work_is_done_in_sequence() {
    //Arrange
    var mock = new Mock<ITarget>();
    var refClass = new RefClass(mock.Object);
    var testClass = new TestClass(mock.Object);

    //Act
    refClass.Work();
    testClass.Work();

    //Assert
    var expected_A_Val = "some_value";
    mock.Verify(_ => _.A(expected_A_Val), Times.Exactly(2));

    var expected_B_Val = 3;
    mock.Verify(_ => _.B(expected_B_Val), Times.Exactly(2));        
}

答案 1 :(得分:0)

如果您只想使用预定义值验证呼叫顺序,则可以使用MockSequence注意 - 您需要使用严格的模拟。测试将在sut.Do()失败,不需要断言:

public void TEST()
{
    //arrange
    var mock = new Mock<ITarget>(MockBehavior.Strict);
    var seq = new MockSequence();
    mock.InSequence(seq).Setup(m => m.A("A1"));
    mock.InSequence(seq).Setup(m => m.A("A2"));
    mock.InSequence(seq).Setup(m => m.B("B1"));
    mock.InSequence(seq).Setup(m => m.B("B2"));

    var sut = new Sut(mock.Object);

    //act
    sut.Do();
 }

如果您不想使用该路线,可以使用回调设置模拟,并在某些列表中添加参数:

[Test]
public void TEST()
{
    //arrange
    var mock = new Mock<ITarget>();
    var calls = new List<Tuple<string, string>>();
    mock.Setup(m => m.A(It.IsAny<string>()))
        .Callback<string>(s => calls.Add(new Tuple<string, string>("A", s)));
    mock.Setup(m => m.B(It.IsAny<string>()))
        .Callback<string>(s => calls.Add(new Tuple<string, string>("B", s)));

    var sut = new Sut(mock.Object);

    //act
    sut.Do();

    //assert
    //inspect calls
}

P.S。我将在两个单独的测试中测试这两个类。