如何模拟具有参数的异步受保护方法?

Nic*_*ico 4 c# unit-testing asynchronous moq protected

这是我要测试的课程:

namespace ClassLibrary1
{
    public class MyBase
    {
        public async Task DoSomething (MyContext context) => await DoSomethingInternal (context);
        public async Task DoSomething() => await DoSomethingInternal();

        protected virtual async Task DoSomethingInternal(MyContext context) { }
        protected virtual async Task DoSomethingInternal() { }
    }

    public class MyContext { }

    public class MyClass : MyBase
    {
        protected override Task DoSomethingInternal(MyContext context) => Task.CompletedTask;
        protected override Task DoSomethingInternal() => Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是测试代码:

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        [ExpectedException(typeof(TaskCanceledException))]
        public async Task TestMethod1()
        {
            var mock = new Mock<MyClass>
            {
                CallBase = true
            };
            mock.Protected().Setup<Task>("DoSomethingInternal", new MyContext()).ThrowsAsync(new TaskCanceledException());
            var obj = mock.Object;

            await obj.DoSomething(null);
        }

        [TestMethod]
        [ExpectedException(typeof(TaskCanceledException))]
        public async Task TestMethod2()
        {
            var mock = new Mock<MyClass>
            {
                CallBase = true
            };
            mock.Protected().Setup<Task>("DoSomethingInternal").ThrowsAsync(new TaskCanceledException());
            var obj = mock.Object;

            await obj.DoSomething();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

结果显示,第一次测试失败,第二次测试成功。调试显示第一个测试的调用返回DoSomethingInternal(context)Task.CompletedTask而不是抛出异常。

那么我怎样才能让它抛出呢?

Nko*_*osi 5

设置中传递的参数与执行测试时传递的实例不匹配。在这种情况下,您需要使用参数匹配器来允许代码按预期流动。

设置受保护成员的期望,如果需要参数匹配,则必须使用ItExpr而不是It

var mock = new Mock<MyClass>() {
    CallBase = true
};

mock.Protected()
    .Setup<Task>("DoSomethingInternal", ItExpr.IsAny<MyContext>())
    .ThrowsAsync(new TaskCanceledException());

var obj = mock.Object;

await obj.DoSomething(null);
Run Code Online (Sandbox Code Playgroud)

参考最小起订量快速入门:其他