使用Moq和MSTest测试异常的正确方法

Sam*_*eeh 4 .net c# unit-testing mstest moq

关于Moq与MsTest的行为有点混淆.

编辑:这不是"如何测试?"的问题.或者"我如何断言?",这是一个便于查看MoQ如何工作的便笺簿,因此不要关注异常类型等.

我认为一个更好的问题可能是=>"Moq投掷<>的行为是否与MsTest ExpectedExceptionAttribute相似?" 也就是说,他们期望在测试或SUT中出现异常?

我想知道当与MsTest一起使用时,MoQ"投掷"的工作原理.不使用MsTest预期的异常属性会更好吗?在测试中执行try..catch是否更好?我还有一些问题需要解决这个问题.

我正在模拟数据库调用,当发生错误时,我想返回零(0).

TestMethod直接使用MsTest异常属性,并且使用Moq抛出异常.它仅在我在SaveCart方法中抛出异常而不是在返回零时才起作用.

我想了解潜在的行为,因为它感觉好像我不应该,也不想在SaveCart方法中抛出异常.

这是测试中的测试:

[TestMethod]
[ExpectedException(typeof(ApplicationException))]
public void CartRepoSaveCartExceptionShouldReturnZero()
{
     _cartDatabaseMock.Setup(c => c.SaveCart(_cart))
                                   .Throws<ApplicationException>();

    var result = _cartRepository.SaveCart(_cart);

    Assert.AreEqual(result, _cartSaveExceptionValue);
}
Run Code Online (Sandbox Code Playgroud)

这是基本的SaveCart,它不会抛出导致测试失败的异常:

public long SaveCart(Cart cart )
{
    long returnValue;

    try
    {
        returnValue = _cartDatabase.SaveCart(cart);
    }
    catch (Exception)
    {
        return 0;
    }
    return returnValue;
}
Run Code Online (Sandbox Code Playgroud)

这是一个基本的SaveCart测试工作,因为它抛出异常:

public long SaveCart(Cart cart )
{
    long returnValue;

    try
    {
        returnValue = _cartDatabase.SaveCart(cart);
    }
    catch (Exception)
    {
        throw new ApplicationException();
    }
    return returnValue;
}
Run Code Online (Sandbox Code Playgroud)

如果问题没有明确解释,请随意为问题提出更好的标题.

Old*_*Fox 7

当被测单元抛出异常时,您应该使用ExpectedExceptionAttribute.

在您的第一个示例中,该方法没有抛出任何异常,因此测试失败.

由于您的测试方法不会抛出任何异常,因此您根本不需要使用此属性...(只需验证此方案中的返回值)

如果要验证是否已抛出异常,并且要验证是否发生了某些其他操作,请使用以下模式:

[TestMethod]
[ExpectedException(typeof(<The specific exception>))]
public void FooTest()
{
    //arrange

    try
    {
       // act
    }
    catch(<the specific exception>)
    {
       // some asserts
       throw;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果出现以下情况,上述代码段将失败:

  1. 提出错误的例外
  2. 没有提出异常
  3. 你的一个断言失败了.

顺便说一句,既然你在方法中没有Exception代替ApplicationException,我提议你将设置更改为:

_cartDatabaseMock.Setup(c => c.SaveCart(_cart)).Throws<Exception>();
Run Code Online (Sandbox Code Playgroud)

  • @SamRabeeh正如我所写的那样,当您的测试单元引发异常时,使用`ExpectedExceptionAttribute`.当您想要模拟依赖项引发异常的场景时,请使用MoQ throws.当你的受抚养者抛出一个异常后,当你的被测单位引发异常时将它们组合在一起.... (2认同)

NKD*_*NKD 2

你是对的 - 第二个测试“SaveCart”有效,因为它抛出异常,而第一个测试失败,因为你正在转向 0。从你对之前答案的回应,我相信你已经知道了这一切。如果您询问第一次测试失败的行为......它是这样的:

  1. SaveCart 被称为
  2. 它返回异常(最小起订量设置的结果)
  3. 你的 try catch 捕获了异常(你故意这样做是为了改变结果)
  4. 你的 try catch 返回 0(结果现在是 0,因为你打算改变它)
  5. 断言根据 _cartSaveExceptionValue 检查您的结果
  6. 您会收到一个失败测试,​​其内容类似于“Message: Assert.AreEqual failed. Expected. Actual<0 (System.Int32)>”。

如果您想仔细检查这一点...您可以尝试以下测试

  1. 注释掉 [ExpectedException(typeof())]
  2. 将 Assert.AreEqual(result, _cartSaveExceptionValue) 更改为 Assert.AreEqual(result, 0);
  3. 测试应该通过,因为您正在将“结果”(又名 0)与 0 进行比较

我希望这能回答你的问题。