为何NUnit单元测试中Find分支全覆盖而Get方法未完全覆盖?
Get方法藏着你没注意的额外分支
别只盯着和Find一致的_dbService.Query调用,仔细检查Get的代码:有没有参数合法性校验(比如ID是否为负、是否为空字符串)?有没有对查询结果的额外处理(比如空结果时返回默认对象还是空值,或者是否有判断结果数量的逻辑)?比如如果Get里写了if (id <= 0) throw new ArgumentException();,但你所有单元测试都传了合法ID,那这个异常分支就没覆盖到,直接拉低分支覆盖率。映射函数的排除规则在Get方法里没生效
虽然MapToUserModel标了[ExcludeFromCodeCoverage],但有些测试工具对不同方法中调用排除函数的分支判定逻辑不一样。比如Find调用映射时工具自动忽略了相关分支,而Get调用时没识别到排除标记,导致把映射相关的分支算进了覆盖率统计里。这种情况可以临时去掉排除标记跑一次测试,看看分支数变化,验证是不是这个问题。测试工具的分支计数细节坑
有些工具会把语法糖拆成多个分支,比如?.空值运算符、??空合并运算符,甚至FirstOrDefault()内部的逻辑都可能被算成分支。比如Get方法如果是return _dbService.Query(...).FirstOrDefault()?.MapToUserModel();,这里的?.就有两个分支:对象不为空时调用映射,为空时返回null。如果你只测了查询结果为空(此时FirstOrDefault返回null,走?.的空分支)和查询结果有一个元素(走非空分支),那应该覆盖,但如果工具把FirstOrDefault()内部的“是否有元素”也算分支,而你没测查询结果有多个元素的场景?不过这种情况概率不高,但可以试试加个多元素的测试用例验证。Get和Find的返回值类型差异导致的分支
比如Get返回单个UserModel,Find返回IEnumerable<UserModel>。如果Get里有var queryResult = _dbService.Query(...); return queryResult.Any() ? MapToUserModel(queryResult.First()) : null;,这里的Any()和三元运算符就有两个分支。如果你测试了queryResult为空(走null分支)和queryResult有一个元素(走映射分支),那是覆盖了,但如果Get里有处理多个元素的逻辑(比如抛出异常),那你没测多元素场景就会漏分支。
内容的提问来源于stack exchange,提问作者Hamid Mayeli

