Moq SetupSequence doesn't work

本文关键字:work SetupSequence doesn Moq | 更新日期: 2023-09-27 18:08:55

我尝试使用Moq 4.5框架的SetupSequence方法。

应该被模拟的类:

public class OutputManager {
    public virtual string WriteMessage(string message) {
    // write a message
    }
}
模拟:

var outputManagerMock = new Mock<OutputManager>();
var writeMessageCalls = 0;
var currentMessage = String.Empty;
outputManagerMock.Setup(o => o.WriteMessage(It.IsAny<string>())).Callback((string m) => {
    writeMessageCalls++;
    message = m;
});

这段代码运行良好。但是我希望对WriteMessage方法的每次调用都有不同的设置。嗯,我用SetupSequence代替Setup:

var outputManagerMock = new Mock<OutputManager>();
var writeMessageCalls = 0;
var firstMessage = String.Empty;
var secondMessage = String.Empty;
outputManagerMock.SetupSequence(o => o.WriteMessage(It.IsAny<string>()))
.Callback((string m) => {
    writeMessageCalls++;
    firstMessage = m;
}).Callback((string m) => {
    writeMessageCalls++;
    secondMessage = m;
});

然后我得到了错误:

方法
的类型参数'SequenceExtensions.SetupSequence<TMock, TResult>(Mock<TMock>, Expression<Func<TMock, TResult>>)'不能从用法中推断出来。
尝试显式指定类型参数。

我在这里找到了可能的解决方案- SetupSequence在Moq。

Moq SetupSequence doesn't work

SetupSequence用于根据尝试使用正在设置的方法的次数设置一个返回序列。一个基于你的代码的例子,它演示了我所说的:

outputManagerMock.SetupSequence(o => o.WriteMessage(It.IsAny<string>()))
.Returns("Hello for the first attempt!")
.Returns("This is the second attempt to access me!")
.Throws(new Exception());

如果OutputManager是其他类的依赖,那么您应该考虑抽象该类,以便更容易模拟您的测试。

public interface IOutputManager {
    string WriteMessage(string message);
}

这就意味着这个接口的实现看起来就像你最初添加这个接口时的样子。

public class OutputManager : IOutputManager {
    public string WriteMessage(string message) {
        // write a message
    }
}

假设您最初试图模拟OutputManager,那么这里的假设是它不是被测试的系统,因为您通常不会模拟测试的目标,而是它的依赖项。

那么让我们假设一个依赖类是这样的:

public class DependentOnIOutputManager {
    private IOutputManager outputManager;
    public DependentOnIOutputManager(IOutputManager outputManager) {
        this.outputManager = outputManager;
    }
    public string SomeMethod(string message) {        
        // write a message
        var output = outputManager.WriteMessage(message);
        //...other code
        return output;
    }
}

那么一个示例测试可能是这样的:

[TestMethod]
public void Moq_SetupSequence_Example() {
    //Arrange
    var mock = new Mock<IOutputManager>();
    mock.SetupSequence(x => x.WriteMessage(It.IsAny<string>()))
        .Returns("first")
        .Returns("second")
        .Throws<InvalidOperationException>();
    var outputManager = mock.Object;
    var sut = new DependentOnIOutputManager(outputManager);
    //Act
    var first = sut.SomeMethod("1st");
    var second = sut.SomeMethod("2nd");
    Exception e = null;
    try {
        sut.SomeMethod("3rd");
    } catch (InvalidOperationException ex) {
        e = ex;
    }
    //Assert
    Assert.IsNotNull(first);
    Assert.IsNotNull(second);
    Assert.IsNotNull(e);
}