我的类中有一个方法,它接收一个函数(Func
)作为参数:
T Execute<T>(Func<T> func)
{
...
return func();
}
我希望模拟这个类,让Moq调用我发送给Execute
的函数作为参数。
我如何致电Execute
:
string result = await executor.Execute(async () => await GetResponse(query));
所以我希望Moq调用GetResponse并返回其值。我怎么能这样做?
答案 0 :(得分:2)
我不完全确定这个问题包含所有信息,因为它非常简单:
public interface I
{
T Execute<T>(Func<T> func);
}
[TestMethod]
public void TestMethod1()
{
var mock = new Mock<I>();
mock.Setup(x => x.Execute<string>(It.IsAny<Func<string>>())).Returns((Func<string> x) => x());
Func<string> myFunc = () => "test";
Assert.AreEqual("test", mock.Object.Execute(myFunc));
}
答案 1 :(得分:1)
首先,如果代码本身已编入您的代码中,则无法模拟它。模拟GetResponse
只有在它是某个外部组件时才有意义。否则,它属于你的班级,不应该嘲笑,但应该在单元测试中进行测试。
要模拟它,请将此代码重构为与此类似。
public class Executor
{
// IResponseProvider has the GetResponse method.
// This interface can be mocked in test and can be injected in real environment.
public IResponseProvider ResponseProvider { get; set; }
public async Task<T> Execute<T>(Func<T> func)
{
var response = await ResponseProvider.GetResponse(query);
// do something with response...
return func();
}
}
现在您可以测试 Executor
类及其Execute
方法,您可以模拟外部IResponseProvider
成员在测试环境中做一些事情:
[TestFixture] // MSTest: [TestClass]
public class ExecutorTest
{
private Executor executor;
private Mock<IResponseProvider> responseProviderMock;
[SetUp] // MSTest: [TestInitialize]
public void Init()
{
// this is not a mock but the class to be tested
executor = new Executor();
// the external components can be mocked, though:
responseProviderMock = new Mock<IResponseProvider>();
// setup the mock:
executor.ResponseProvider = responseProviderMock.Object;
Func<string> mockResponse = () => "dummy mocked response";
responseProviderMock.Setup(m => m.GetResponse(It.IsAny<MyQueryType>))
.Returns(Task.FromResult(mockResponse));
}
[Test] // MSTest: [TestMethod]
public async Task ExecuteSuccessTest()
{
// Arrange
Func<int> input = () => 42;
// Act
var result = executor.Execute(input);
// Assert
Assert.AreEqual(42, result);
responseProviderMock.Verify(rp => rp.GetResponse(It.IsAny<MyQueryType>(), Times.Once);
}
}