47

我使用 MOQ 框架进行测试。我有一个场景,我希望抛出一个错误异常。我如何验证它是否被抛出?

public void Koko(List<string?> list) 
{ 
   foreach(string? str in list) 
   { 
        if (str != null) someProperty.Foo(str); 
        else throw new FormatException(); 
   } 
} 

提前致谢。

4

7 回答 7

59

如果您想验证是否引发了异常(由您自己的代码),那么 Moq 不是您选择的工具。只需使用可用的单元测试框架之一。

Xunit/NUnit:

Assert.Throws<SomeException>(() => foo.Bar());

流利的断言:

Action act = () => foo.Bar();
act.Should().Throw<SomeException>();
               

https://fluentassertions.com/introduction

http://www.nunit.org/index.php?p=exceptionAsserts&r=2.6.2

于 2013-04-17T08:14:04.430 回答
29

我可能误读了您的意图,但据我所知,没有必要对模拟做任何事情来测试是否引发了异常。

看起来你有一个类,它的方法 Foo 接受一个字符串 - 让我们调用这个 InnerClass

public class InnerClass {
    public virtual void Foo(string str) {
         // do something with the string
    }
}

和一个包含 InnerClass 作为属性 (someProperty) 的类,它有一个成员 Koko,它以 List<string> 作为参数

public class OuterClass {

    private readonly InnerClass someProperty;

    public OuterClass(InnerClass someProperty) {
        this.someProperty = someProperty;
    }

    public void Koko(List<string> list) {
         foreach (var str in list) {
              if (str != null)
                   someProperty.Foo(str);
              else
                   throw new FormatException();
          }
    } 
}

注意:我无法让 List<string?> 编译 - 告诉我基础类型(字符串)必须是不可为空的。AFAIK,只需要使值类型可以为空,引用类型可以隐式为空。

看起来您想测试如果您传入一个字符串列表,其中任何一个为空,则抛出 FormatException。

如果是这样,那么 MOQ 的唯一原因就是让我们不必担心 InnerClass 功能。Foo 是一种方法,因此,除非我们使用严格的模拟,否则我们可以只创建一个 InnerClass 模拟而无需其他设置。

有一个属性[ExpectedException],我们可以使用它标记我们的测试以验证是否已抛出异常。

[TestMethod]
[ExpectedException(typeof(FormatException))]
public void ExceptionThrown() {

    var list = new List<string>() {
        "Abel",
        "Baker",
        null,
        "Charlie"
    };

    var outer = new OuterClass(new Mock<InnerClass>().Object);
    outer.Koko(list);

}

如果抛出 FormatException,则此测试将通过,否则将失败。

于 2013-04-18T09:16:27.250 回答
14

通读这些答案,我意识到还有另一种方法可以使用 NUnit 来做到这一点。下面从异常中获取异常文本并验证错误消息文本。

var ex = Assert.Throws<SomeException>(() => foo.Bar());
Assert.That(ex.Message, Is.EqualTo("Expected exception text");

而且我无法使用最新版本的 NUnit 使装饰/属性语法正常工作(上面 AlanT 的回答)——不知道为什么,但无论我尝试做什么,它都会抱怨。

于 2018-08-03T22:14:15.710 回答
12

您可以使用 NUnit Asserts 测试是否引发了异常:

Assert.That(() => testObject.methodToTest(), Throws.TypeOf<FaultException>());
于 2013-04-17T07:00:58.470 回答
12

请阅读此起订量简介。这是调用方法时设置InvalidOperationException抛出的方法:DoSomething

mock.Setup(foo => foo.DoSomething()).Throws<InvalidOperationException>();

然后简单地验证是否调用了方法。如果它被调用,则引发异常

mock.Verify(foo => foo.DoSomething());
于 2013-04-17T06:56:47.117 回答
9

一个老问题,但没有源代码实际显示解决方案是什么,所以这就是我所做的:

var correctExceptionThrown = false;

try
{
    _myClass.DoSomething(x);
}
catch (Exception ex)
{
    if (ex.Message == "Expected message")
        correctExceptionThrown = true;
}                    

Assert.IsTrue(correctExceptionThrown);

请注意,您可以捕获特定类型的异常(通常更可取),而不是检查消息。

于 2016-10-03T11:13:47.697 回答
2

好的,所以我通过以下方式解决了它。

由于异常破坏了我的测试,我将方法调用放在 try-catch 的因为块中。

然后我可以使用一个简单的验证。

感谢所有的帮助者...

于 2013-04-17T08:36:55.913 回答