调用函数的设置方法
Setup method to invoke function
我的 class 中有一个方法接收函数 (Func
) 作为参数:
T Execute<T>(Func<T> func)
{
...
return func();
}
我想模拟这个 class,并让 Moq 调用我作为参数发送给 Execute
的函数。
我怎么称呼Execute
:
string result = await executor.Execute(async () => await GetResponse(query));
所以我希望 Moq 调用 GetResponse 并 return 它的值。我该怎么做?
我不完全确定问题是否包含所有信息,因为它真的很简单:
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));
}
首先,如果代码本身被嵌入到您的代码中,您就不能模拟它。模拟 GetResponse
仅当它是某个外部组件时才有意义。否则,它属于您的 class,不应模拟,但应在单元测试中进行测试。
要模拟它,请按照与此类似的方式重构您的代码。
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
class 及其 Execute
方法,并且您可以 mock 外部 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);
}
}
我的 class 中有一个方法接收函数 (Func
) 作为参数:
T Execute<T>(Func<T> func)
{
...
return func();
}
我想模拟这个 class,并让 Moq 调用我作为参数发送给 Execute
的函数。
我怎么称呼Execute
:
string result = await executor.Execute(async () => await GetResponse(query));
所以我希望 Moq 调用 GetResponse 并 return 它的值。我该怎么做?
我不完全确定问题是否包含所有信息,因为它真的很简单:
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));
}
首先,如果代码本身被嵌入到您的代码中,您就不能模拟它。模拟 GetResponse
仅当它是某个外部组件时才有意义。否则,它属于您的 class,不应模拟,但应在单元测试中进行测试。
要模拟它,请按照与此类似的方式重构您的代码。
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
class 及其 Execute
方法,并且您可以 mock 外部 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);
}
}