如何用正确的参数测试方法的调用
本文关键字:测试方法 调用 参数 何用正 | 更新日期: 2023-09-27 17:50:37
我有一个方法,它调用一个模拟对象的另一个方法,该方法的参数是根据我传递给测试函数的参数计算的。
如何验证被测试方法所调用的方法是否被正确调用?
我正在使用Moq
编辑:
因为你们没有人明白我的意思(或者因为我不明白你们为我解决了这个问题),我会更具体一些。
我有以下方法签名:
IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state);
内部应该实例化一个SocketAsyncEventArgs对象,并使用正确的SocketAsyncEventArgs调用它的SetBuffer方法。
SocketAsyncEventArgs是一个实现细节,但它是实现我之后的功能的唯一方法,所以我必须检查它的SetBuffer方法是否被正确调用。我如何确保BeginWrite()实现实际上调用SetBuffer正确的参数?
编辑2:
下面是一些代码来澄清我的意思:
public IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state)
{
// No mocking can be done here
SocketAsyncEventArgs args = new SocketAsyncEventArgs
{
// Proper initialization. Should be verified as well.
};
args.SetBuffer(buffer, offset, size);
Client.SendAsync(args);
}
您可以测试是否通过Verify
方法调用该方法。如果被调用的方法没有返回任何东西,那么就不需要Setup
。与Setup或Expect/VerifyAll方法相比,我更喜欢这种方法,因为它更具有AAA性。
[Test]
public void ShoudlCallMockMethod()
{
var mocked = new Mock<IDoStuff>();
var target = new ClassToTest(mocked.Object);
target.DoStuff();
mocked.Verify(x => x.CallMyMethod(It.IsAny<string>());
}
在这里,它期望调用任何参数的CallMyMethod
。如果您知道传入的确切参数并想要检查,那么执行
mocked.Verify(x => x.CallMyMethod("exactstring"));
如果你想要更复杂的匹配传入的内容(对于具有许多参数的复杂对象很有用),然后看看我使用匹配器做的另一个答案。
你也可以添加Times.AtMostOnce()如果你想确保它只被调用一次
[编辑]根据你的编辑和注释,你不需要模拟args对象,但如果你仍然想验证参数是否设置,那么你可以在客户端上验证。SendAsync方法,前提是可以模拟(我建议你应该瞄准,如果你还没有这样做)。我提供的关于匹配器的链接应该会有所帮助。
关于你在过去几年的评论中提出的问题,已经从记录/重播-验证>期望/设置-验证>[设置]-验证转变。这可以归结为模拟技术,但主要是由于c#3.5中引入了lambda表达式,然后转向了AAA。你真正想要的是遵循AAA原则的小型可读测试,因此拥有Expect/Setup-VerifyAll实际上是在安排阶段拥有Assert(你必须回头看看正在验证什么)。因此,除非模拟方法需要返回一些东西,否则您不需要设置,只需验证该方法是否在Assert阶段被调用。
我相信它会验证您在调用Setup
时传递的参数等于实际代码传递的参数。
快速入门指南中有更有趣的约束示例。不幸的是,到外部API指南的链接目前正在失败:(
编辑:我怀疑你想要这样的东西:
mock.Setup(foo => foo.SendAsync(It.Is<AsyncCallback>(x =>
{
// Whatever you need to test here
return x.Buffer.Length == 15 &&
x.Offset = 10 &&
x.Count = 5;
}));
下面的测试失败是由于参数value作为"expected"传递的设置期望没有得到满足。我想这就是你想要的?
[TestClass]
public class MyTests
{
[TestMethod]
public void TestParameterExpectation()
{
var mock = new Mock<IInterface>();
mock.Setup(x => x.CallMe("expected"));
CallIt("not expected", mock.Object);
mock.VerifyAll();
}
public void CallIt(string value, IInterface callit)
{
callit.CallMe(value);
}
}
public interface IInterface
{
void CallMe(string value);
}