You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用NUnit测试Catch块满足Sonar覆盖率?测试失败求解

问题:NUnit测试Catch块覆盖率失败,报错“Expected: <System.Exception> But was: null”

我是NUnit(3.4+)新手,希望编写NUnit测试用例确保代码中的Catch块被Sonar覆盖率统计到,但尝试的方案均失败,报错“Expected: <System.Exception> But was: null”。

被测方法代码:

public async Task<List<ReturnObjects>> GetData(int Id)
{
   try
   {
       // 实际代码会调用_queryHelperDataMart.WrapQueryAsync
   }
   catch(Exception)
   {
       // 处理异常逻辑,未重新抛出
   }
}

我的测试用例代码:

[Test]
public async Task CanCallGetData_Test_ThrowsException()
{
    // Arrange
    var Id = 927810493;
    List<ReturnObjects> objs = null; //尝试通过空引用触发异常

    //模拟仓储类数据
    _queryHelperDataMart.Setup(mock => mock.WrapQueryAsync<ReturnObjects> 
    (It.IsAny<string>(), It.IsAny<IConfiguration>(), It.IsAny<Dictionary<string, 
    object>>(), 
    It.IsAny<string>())).ReturnsAsync(objs);

    // Act
    var result = Assert.ThrowsAsync<Exception>(() => _testClass.GetData(Id));

    // Assert
    Assert.That(result, ..check exception etc);
} 

请问我哪里出错了?另外,当无法从测试方法生成实际异常时,该如何编写测试用例覆盖Catch块?


解答

错误原因分析

  1. 测试方向错误:被测方法的Catch块没有重新抛出异常,方法执行时即使进入Catch块,也不会向外抛出异常。但你用了Assert.ThrowsAsync<Exception>,它期望方法会抛出异常,自然会失败。
  2. 未真正触发异常:你让Mock返回null,但如果被测方法的try块里没有代码会因为null抛出异常(比如空的try块,或者调用WrapQueryAsync返回null后没有后续操作),根本不会进入Catch块。

修正方案

1. 让Mock抛出异常,触发Catch块

要进入Catch块,必须让try块内的代码抛出异常。把Mock的ReturnsAsync(objs)改成ThrowsAsync,直接抛出异常:

// Arrange部分修正
_queryHelperDataMart.Setup(mock => mock.WrapQueryAsync<ReturnObjects>(
    It.IsAny<string>(), 
    It.IsAny<IConfiguration>(), 
    It.IsAny<Dictionary<string, object>>(), 
    It.IsAny<string>()))
.ThrowsAsync(new Exception("测试异常"));

2. 调整测试逻辑,适配方法吞异常的行为

因为被测方法不会向外抛异常,所以不能用Assert.ThrowsAsync,直接调用方法后验证其行为:

[Test]
public async Task GetData_WhenThrowsException_CoversCatchBlock()
{
    // Arrange
    var Id = 927810493;
    _queryHelperDataMart.Setup(mock => mock.WrapQueryAsync<ReturnObjects>(
        It.IsAny<string>(), 
        It.IsAny<IConfiguration>(), 
        It.IsAny<Dictionary<string, object>>(), 
        It.IsAny<string>()))
    .ThrowsAsync(new Exception());

    // Act
    var result = await _testClass.GetData(Id);

    // Assert
    // 根据Catch块的实际逻辑验证返回值,比如如果Catch里返回空列表:
    Assert.That(result, Is.Empty);
    // 验证Mock方法确实被调用过,确保流程走到了try块
    _queryHelperDataMart.Verify(mock => mock.WrapQueryAsync<ReturnObjects>(
        It.IsAny<string>(), 
        It.IsAny<IConfiguration>(), 
        It.IsAny<Dictionary<string, object>>(), 
        It.IsAny<string>()), Times.Once);
}

通用技巧:覆盖Catch块的核心要点

  • 确保try块抛出异常:不管是Mock依赖抛出异常,还是构造特定参数触发业务异常,核心是让try块内的代码执行时抛出目标异常类型。
  • 不要依赖Assert.ThrowsAsync:如果被测方法吞了异常,测试重点应放在验证异常处理后的行为(比如返回值、日志、状态变化等),而非捕获向外抛出的异常。
  • 用Verify验证流程:通过Moq的Verify方法确认依赖方法被调用,确保代码确实走到了try块,进而触发Catch块。

内容的提问来源于stack exchange,提问作者MB22

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 14:25:13