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

Posted

技术标签:

【中文标题】如何模拟具有参数的异步受保护方法?【英文标题】: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,而不是抛出异常。

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

【问题讨论】:

【参考方案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

【讨论】:

就像一个魅力。非常感谢。

以上是关于如何模拟具有参数的异步受保护方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 javascript 类中模拟受保护的变量?

Easymock:如何在不可见的情况下模拟受保护方法的调用

是否可以模拟受保护的属性和方法

PHP单元测试,带模拟的受保护方法

C#:在密封类中模拟和测试受保护(或私有)方法——方法

忽略 Moq 中受保护方法的 List 类型的参数