在Nunit,C#中验证ArgumentException及其消息

Hen*_*ang 31 c# nunit assert exception

在我在Nunit的测试程序中,我想通过验证消息来验证它是否正在获取写入Argument Exception.

    [Test]
    public void ArgumentsWorkbookNameException()
    {
        const string workbookName = "Tester.xls";
        var args = new[] { workbookName, "Sheet1", "Source3.csv", "Sheet2", "Source4.csv" };
        Assert.Throws(typeof(ArgumentException), delegate { var appargs = new ApplicationArguments(args); }, "Invalid ending parameter of the workbook. Please use .xlsx");

    }
Run Code Online (Sandbox Code Playgroud)

在测试完之后,当我在主程序中修改消息时,这不起作用.

        int wbLength = args[0].Length;

        // Telling the user to type in the correct workbook name file.
        if (args[0].Substring(wbLength-5,5)!=".xlsx")
        {
            throw new ArgumentException(
                "Invalid ending parameter of the workbook. Please use .xlsx random random");
        }
Run Code Online (Sandbox Code Playgroud)

无论我是否更改了消息,单元测试仍然通过.

我该怎么做?或者C#中没有这样的东西.我的同事说Ruby和RSPEC都有类似的选项,但他对C#并不是100%肯定.

Ple*_*ntD 49

使用fluent接口创建断言:

Assert.That(() => new ApplicationArguments(args), 
    Throws.TypeOf<ArgumentException>()
        .With.Message.EqualTo("Invalid ending parameter of the workbook. Please use .xlsx random random"));
Run Code Online (Sandbox Code Playgroud)


Dar*_*iak 24

我同意Jon的观点,"这种测试不必要地脆弱".但是,至少有两种方法可以检查异常消息:

1:Assert.Throws返回一个异常,因此你可以为它的消息做一个断言:

var exception = Assert.Throws<ArgumentException>(() => new ApplicationArguments(args));
Assert.AreEqual("Invalid ending parameter of the workbook. Please use .xlsx random random", exception.Message);
Run Code Online (Sandbox Code Playgroud)

2:您还可以使用ExpectedException属性.但是,请注意,属性在整个测试代码中等待异常,而不仅仅是在抛出异常的代码中除外.因此,不建议使用此属性.

[Test]
[ExpectedException(typeof(ArgumentException), ExpectedMessage = "Invalid ending parameter of the workbook. Please use .xlsx random random")]
public void ArgumentsWorkbookNameException()
{
    const string workbookName = "Tester.xls";
    var args = new[] { workbookName, "Sheet1", "Source3.csv", "Sheet2", "Source4.csv" };
    new ApplicationArguments(args);
}
Run Code Online (Sandbox Code Playgroud)

  • 我个人会避免使用`ExpectedExceptionAttribute`.`Assert.Throws`更准确地说明错误的确切位置*.如果OP*真的想要测试异常消息,那么他们最好还是编写自己的`MoreAssertions.Throws`或其他什么. (3认同)

Jon*_*eet 5

中的消息参数Assert.Throws不是预期的异常消息;如果测试失败,它是包含在断言失败中的错误消息。

我不认为 N​​Unit 支持开箱即用地测试异常消息,并且我认为此类测试无论如何都是不必要的脆弱。如果您确实想编写自己的此类辅助方法,您可以这样做,但我个人不鼓励这样做。(我也很少指定测试失败消息,除非它包含一些诊断信息。如果测试失败,我无论如何都会查看测试,因此该消息不会添加太多内容。)

为了简单起见,我鼓励您使用泛型重载和 lambda 表达式:

Assert.Throws<ArgumentException>(() => new ApplicationArguments(args));
Run Code Online (Sandbox Code Playgroud)

(顺便说一下,如果这是您的实际代码,那么还有其他问题 - 尝试new[] { "xyz" }作为参数传递......)

  • 但是,是否不值得验证并检查消息,确保您正在测试的异常是您想要的异常,而不是代码中不同点的其他异常?如果相同的异常类型但来自不同的地方,则您的代码可能会执行您不希望它执行的操作。 (3认同)
  • 另一种方法是将常量存储在公共位置或类中,并使生产代码和测试代码都指向同一位置。如果消息需要更改,只需在该位置进行更改即可。 (2认同)