我的服务层
中有以下方法public ModuleResponse GetModules(ModuleRequest request)
{
var response = new ModuleResponse(request.RequestId);
try
{
response.Modules = Mapper.ToDataTransferObjects(ModuleDao.GetModules());
return response;
}
catch (Exception ex)
{
Log.Error(ex);
response.Acknowledge = AcknowledgeType.Failure;
response.Message = "An error occured.";
return response;
}
}
我有一个用xUnit编写的单元测试,如下所示:
[Fact]
public void GetModulesTest()
{
//Arrange
var mockModuleDao = Mock.Create<IModuleDao>();
var mockLog = Mock.Create<ILog>();
var mockAuditDao = Mock.Create<IAuditDao>();
var moduleList = new List<ModuleItem>
{
new ModuleItem {Id = 100, Category = "User Accounts", Feature = "Users"},
new ModuleItem {Id = 101, Category = "User Accounts", Feature = "Roles Permissions"}
};
mockModuleDao.Arrange(dao => dao.GetModules()).Returns(moduleList);
IUserManagementService userService = new UserManagementService(mockModuleDao, mockLog, mockAuditDao);
var request = new ModuleRequest().Prepare();
//Act
var actualResponse = userService.GetModules(request);
//Assert
Assert.Equal(AcknowledgeType.Success, actualResponse.Acknowledge);
Assert.Equal(2, actualResponse.Modules.Count);
}
现在我的代码中有另外一堆检索方法,类似于上面的方法。
测试此类方法是否多余?我的意思是,它们几乎是一个肯定的通过测试,除非我弄乱了我的Mapping或其他东西的逻辑。
另外,在测试检索方法时,我应该测试什么?在上面的场景中,我有2个断言语句,1个用于检查响应是否成功,第2个用于检查列表的计数。
这足够吗?或者如何进一步改进以提高这种单元测试的价值?
答案 0 :(得分:5)
与往常一样,这样的测试是否有价值取决于您的测试动机。
失败的成本越高,测试一段代码就越重要。
GetModules
方法至少做了四件事:
GetModulesTest
测试这四项职责中的单个,这意味着仍需要其他三项测试才能完全涵盖GetModules
方法。
编写小粒度单元测试很有价值,因为它可以将复杂的生产代码分解为一组简单易懂的单元测试。有时候,这些单元测试几乎变得非常简单,以至于你开始怀疑它的价值,但是在单个单元测试中它的价值不是 - 它在积累中简单的测试,它们一起指定整个系统应该如何工作。
答案 1 :(得分:3)
现在我的代码中有另外一堆检索方法,类似于上面的方法。
真的?他们觉得有点......重复吗?
我认为Lilshieste提出了一个非常恰当的观点,即单元测试的一个内在价值是它们突出了这样的可维护性问题。你可能会说他们让代码闻起来更刺鼻。
Mark Seemann确定了您向我们展示的这一方法的四个个人责任。单一责任原则将规定您应该只有一个。
你可以想象将这种方法(及其所有亲属)变成更像这样的东西:
public ModuleResponse GetModules(ModuleRequest request)
{
return _responder.CreateMappedDtoResponse(
request,
ModuleDao.GetModules,
modules => new ModuleResponse {Modules = modules}));
}
现在,在这一点上,我认为你可以对这种方法进行单元测试。您几乎都在测试此方法的实现,而不是其行为。你的单元测试将测试你用给定的参数调用给定的方法,那就是它!
但即使你决定成为一个纯粹主义者和单位测试者,你真的只能进行一次单元测试,而不是之前你需要完全覆盖这种方法的四种单元测试。然后你为CreateMappedDtoResponse
方法(以及它可能将其部分工作委托给它的任何方法)编写适当的单元测试,并且你已经得到了一个干燥,经过良好测试的系统,其中只有一小部分是试验。如果您更改了异常日志记录策略等常见责任,则可以在一个位置更改它,更改一个单元测试并完成。
因此,即使您的单元测试从未为您捕获过一个错误,作为一个纯粹主义者帮助您避免可维护性问题,这可能会导致您首先编写额外的代码,并且可能会重写和以后一样多的代码。当然,只有当您知道听取单元测试并相应地更改设计时才会发生这种情况。