在私有委托方法中测试异常

时间:2020-03-08 17:44:52

标签: c# wpf unit-testing exception mvvm

我正在以MVVM方式设计WPF应用程序,但遇到一个问题,即如何测试当另一个视图模型发送消息时引发了异常。我正在使用nUnit进行单元测试。

我尝试测试当通过Messenger发送的对象为null时,委托是否引发异常。

请在下面找到简单的代码
CTOR (所有依赖项都使用Autofac注入)

    public ManagerViewModel (IMessenger messenger)
    {
       messenger.Register<Person> (this, OnPersonSent)
    }

代理

    private void OnPersonSent()
    {
       if(Person is null) throw new ArgumentNullException();
    }


单元测试
当我尝试如下声明时,它不会捕获异常。情况是,当Messenger发送消息时,OnPersonSent方法应该引发异常-但是如何使用Assert捕获它。如果此断言仅捕获由lambda表达式传递的方法引发的异常,则抛出该异常(如果我错了,请更正我) 。下面的测试用例:

    [SetUp]
    public void SetUp()
    {
      messenger = new Messenger() // MVVMLight messenger
      sut = new ManagerViewModel(messenger)
    }

下面在lambda表达式中,我正在发送空对象,以抛出上面所指向的委托引发的异常

    [Test] 
    public void OnPersonSent_WhenNull_ThrowsException()
    {    
           Assert.Throws<ArgumentNullException>(()=>messenger.Send((Person)null));
    }

非常感谢您的帮助。

PS。当然,此案例经过简化以清楚地表明问题所在

1 个答案:

答案 0 :(得分:1)

查看以下最小示例,以了解如何测试预期行为的委托调用

注意:(使用MOQ模拟框架模拟依赖项。)

[TestClass]
public class MyTestClass {
    [TestMethod]
    public void OnPersonSent_WhenNull_ThrowsException() {
        //Arrange
        var mock = new Mock<IMessenger>();
        Action<Person> callback = null;
        //setup the mock so the delegate can be captured when registered
        mock
            .Setup(_ => _.Register(It.IsAny<object>(), It.IsAny<Action<Person>>(), It.IsAny<bool>()))
            .Callback((object obj, Action<Person> action, bool _) => {
                callback = action; //<--
            });

        //Act
        //create view model to invoke register and capture callback in mock
        var sut = new ManagerViewModel(mock.Object);

        //Assert
        Assert.IsNotNull(callback);
        Assert.ThrowsException<ArgumentNullException>(() => callback(null));
    }
}

public class ManagerViewModel {
    public ManagerViewModel(IMessenger messenger) {
        messenger.Register<Person>(this, OnPersonSent);
    }

    private void OnPersonSent(Person person) {
        if (person is null) throw new ArgumentNullException();
    }
}

internal class Person {
}

已创建并设置了Messenger的模拟程序,以期望调用适当的Register成员。该模拟程序的设置是为了捕获主题类的构造函数中提供的委托方法。

捕获到委托后,就可以调用它并声明预期的行为。

在测试中调用委托与调用Send时实际的Messenger调用注册的委托时相同。

上面显示的方法在单元测试中隔离了调用。

请注意,上述测试使用默认的MSTest,但可以轻松应用于其他测试框架。