Moq SetupSequence 不起作用
Moq SetupSequence doesn't work
我尝试使用Moq 4.5框架的SetupSequence
方法
Class 应该被嘲笑的:
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;
});
然后我得到了错误:
Error CS0411 The type arguments for method
'SequenceExtensions.SetupSequence<TMock, TResult>(Mock<TMock>,
Expression<Func<TMock, TResult>>)'
cannot be inferred from the usage.
Try specifying the type arguments explicitly.
我在这里找到了可能的解决方案 - SetupSequence in Moq。但它看起来像是一种解决方法。
SetupSequence 用于根据尝试使用正在设置的方法的次数设置 returns 的序列。基于您的代码的示例演示了我在说什么:
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
是其他 classes 的依赖项,那么您应该考虑抽象化 class 以便更容易模拟您的测试。
public interface IOutputManager {
string WriteMessage(string message);
}
那就意味着这个接口的实现看起来就像你最初添加接口的样子。
public class OutputManager : IOutputManager {
public string WriteMessage(string message) {
// write a message
}
}
鉴于您最初尝试模拟 OutputManager
那么这里的假设是它不是被测系统,因为您通常不模拟测试目标而是模拟其依赖项。
所以让我们假设一个受抚养人 class 看起来像这样。
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);
}
我尝试使用Moq 4.5框架的SetupSequence
方法
Class 应该被嘲笑的:
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;
});
然后我得到了错误:
Error CS0411 The type arguments for method
'SequenceExtensions.SetupSequence<TMock, TResult>(Mock<TMock>, Expression<Func<TMock, TResult>>)'
cannot be inferred from the usage.
Try specifying the type arguments explicitly.
我在这里找到了可能的解决方案 - SetupSequence in Moq。但它看起来像是一种解决方法。
SetupSequence 用于根据尝试使用正在设置的方法的次数设置 returns 的序列。基于您的代码的示例演示了我在说什么:
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
是其他 classes 的依赖项,那么您应该考虑抽象化 class 以便更容易模拟您的测试。
public interface IOutputManager {
string WriteMessage(string message);
}
那就意味着这个接口的实现看起来就像你最初添加接口的样子。
public class OutputManager : IOutputManager {
public string WriteMessage(string message) {
// write a message
}
}
鉴于您最初尝试模拟 OutputManager
那么这里的假设是它不是被测系统,因为您通常不模拟测试目标而是模拟其依赖项。
所以让我们假设一个受抚养人 class 看起来像这样。
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);
}