【问题标题】:How can I mock an async protected method that has a parameter?如何模拟具有参数的异步受保护方法?
【发布时间】:2019-03-31 22:59:46
【问题描述】:

这是我要测试的课程:

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;
    }
}

这是测试代码:

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();
        }
    }
}

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

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

【问题讨论】:

    标签: c# unit-testing asynchronous moq protected


    【解决方案1】:

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

    为受保护的成员设置期望值,如果您需要参数匹配,您必须使用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);
    

    参考Moq Quickstart: Miscellaneous

    【讨论】:

    • 就像一个魅力。非常感谢。
    猜你喜欢
    • 2016-09-25
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 2016-03-09
    • 2016-05-29
    • 1970-01-01
    • 2016-03-17
    相关资源
    最近更新 更多