MOQ - 验证异常被抛出

Gal*_*Ziv 25 c# unit-testing moq

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

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

提前致谢.

tre*_*eze 29

如果你想验证抛出异常(通过你自己的代码),那么Moq不是你选择的工具.只需使用其中一个单元测试框架即可.

的xUnit/NUnit的:

Assert.Throws<SomeException>(() => foo.Bar());
Run Code Online (Sandbox Code Playgroud)

流利断言:

Action act = () => foo.Bar();
act.ShouldThrow<SomeException>();
Run Code Online (Sandbox Code Playgroud)

http://fluentassertions.codeplex.com/documentation

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

  • 如果您使用的是最新的 FluentAssertions 包,您将验证是否抛出了如下异常: Action action = () =&gt; foo.Bar(); Action.Should().Throw&lt;Exception&gt;(); (3认同)
  • @Lukas FluentAssertions 对这种情况有很好的支持 `Func&lt;Task&gt; act = () =&gt; foo.BarAsync(); 等待 act.Should().ThrowAsync&lt;SomeException&gt;();` (2认同)

Ala*_*anT 25

我可能会误读你的意图,但据我所知,没有必要对mock进行任何操作以测试异常是否被抛出.

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

public class InnerClass {
    public virtual void Foo(string str) {
         // do something with the string
    }
}
Run Code Online (Sandbox Code Playgroud)

和一个包含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();
          }
    } 
}
Run Code Online (Sandbox Code Playgroud)

注意:我无法获得List <string?>进行编译 - 告诉我底层类型(字符串)必须是非可空的.AFAIK,只需要使值类型可以为空,引用类型可以隐式为空.

看起来你想测试一下,如果你传入一个字符串列表,其中任何一个字符串都是null,抛出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);

}
Run Code Online (Sandbox Code Playgroud)

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

  • 这是真正的答案。谢谢 (2认同)

Ser*_*kiy 11

请阅读本Moq简介.以下是调用方法InvalidOperationException时设置throw的DoSomething方法:

mock.Setup(foo => foo.DoSomething()).Throws<InvalidOperationException>();
Run Code Online (Sandbox Code Playgroud)

然后只需验证方法是否被调用.如果它被调用,则引发异常

mock.Verify(foo => foo.DoSomething());
Run Code Online (Sandbox Code Playgroud)


g t*_*g t 11

您可以使用NUnit Asserts测试抛出异常:

Assert.That(() => testObject.methodToTest(), Throws.TypeOf<FaultException>());
Run Code Online (Sandbox Code Playgroud)


Ron*_*nie 7

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

var correctExceptionThrown = false;

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

Assert.IsTrue(correctExceptionThrown);
Run Code Online (Sandbox Code Playgroud)

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


Dav*_*N59 6

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

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

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