如何用正确的参数测试方法的调用

本文关键字:测试方法 调用 参数 何用正 | 更新日期: 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);
}