如何单元测试值取决于 MessageBox?

How to unittest value depends on MessageBox?

我使用 NUnit 来测试单元,我有一个方法:

class abc
{
    private int a;
    public void myMethod()
    {
         if(MessageBox.Show("Sure?", "Title", MessageBoxButtons.YesNo) == DialogResult.Yes)
             a = 1;
         else
             a = 0;
    }
}

如何编写 NUnit 来测试此方法?对不起我的英语不好。 非常感谢。

通常的解决方案是模拟 MessageBox class 并模拟 Show 方法 returns。由于它是一个静态方法,因此需要对代码进行额外的工作和一些修改。这是一个可能的解决方案:

创建一个封装Show方法的class:

public class MyMessageBox {
    public virtual DialogResult Show(string text, string caption, MessageBoxButtons buttons) {
        return MessageBox.Show(text, caption, buttons);
    }
}

然后修改您的代码以使用 class:

class Abc {
    internal int a;
    private readonly MyMessageBox messageBox;

    public Abc(MyMessageBox messageBox) {
        this.messageBox = messageBox;
    }

    public void MyMethod() {
        if (messageBox.Show("Sure?", "Title", MessageBoxButtons.YesNo) == DialogResult.Yes)
            a = 1;
        else
            a = 0;
    }
}

之后,您可以编写模拟 MyMessageBox class 的测试。我在下面的示例中使用 NSubstitute

[Test]
public void Test() {
    MyMessageBox messageBox = Substitute.For<MyMessageBox>();
    messageBox.Show("Sure?", "Title", MessageBoxButtons.YesNo).Returns(DialogResult.Yes);

    Abc abc = new Abc(messageBox);
    abc.MyMethod();

    Assert.AreEqual(1, abc.a);
}

这是一种方法。值不值得由你来决定。

我建议使用一些设计模式来实现这一点。

--MVVM(有一个很棒的库,叫做 MVVMLight,你可以从 Nuget 得到它)

--依赖注入

--控制反转

--存储库模式

因此,对 MessageBox 的调用仅存在于顶层视图中。像这样--

Messenger.Default.Register<DialogMessage>(this, ProcessMessage);

    private static void ProcessMessage(DialogMessage message)
    {
        var result = MessageBox.Show(
                        message.Content,
                        message.Caption,
                        message.Button);

        message.Callback(result);
    }

所以,现在当您 运行 单元测试时--

    [Test]
    public void Some_Test ()
    {
        //Arrange
        string expected_msg = "";
        Messenger.Default.Register<DialogMessage>(this, (o) => {expected_msg=o.Content ;}); 
        CreateSUT();

        //Act
        ..do something here that involves calling that MessageBox

        //Assert

        Assert.That(expected_msg, Is.EqualTo(<Some Msg you are sending from ViewModel>));
    }

当以这样的方式从 ViewModel 调用时,此单元测试捕获对 MessageBox 的调用--

Messenger.Default.Send(new DialogMessage("<Some Message you are sending from viewmodel>", delegate { })
            {
                Button = MessageBoxButton.OK,
                Caption = "Alert",
                Icon = MessageBoxImage.Exclamation
            });