单元测试检索方法 - 冗余?

时间:2014-04-23 01:49:46

标签: c# .net unit-testing mocking xunit.net

我的服务层

中有以下方法
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个用于检查列表的计数。

这足够吗?或者如何进一步改进以提高这种单元测试的价值?

2 个答案:

答案 0 :(得分:5)

与往常一样,这样的测试是否有价值取决于您的测试动机。

  • 这段代码对任务至关重要吗?
  • 如果代码失败会有什么代价?
  • 如果出现错误,您能轻松解决错误吗?

失败的成本越高,测试一段代码就越重要。

GetModules方法至少做了四件事:

  • 它返回DAO中的模块。
  • 它将DAO中的模块映射到所需的返回类型。
  • 如果出现问题,则会返回错误消息。
  • 记录可能发生的任何错误。

GetModulesTest测试这四项职责中的单个,这意味着仍需要其他三项测试才能完全涵盖GetModules方法。

编写小粒度单元测试很有价值,因为它可以将复杂的生产代码分解为一组简单易懂的单元测试。有时候,这些单元测试几乎变得非常简单,以至于你开始怀疑它的价值,但是在单个单元测试中它的价值不是 - 它在积累中简单的测试,它们一起指定整个系统应该如何工作。

答案 1 :(得分:3)

  

现在我的代码中有另外一堆检索方法,类似于上面的方法。

真的?他们觉得有点......重复吗?

我认为Lilshieste提出了一个非常恰当的观点,即单元测试的一个内在价值是它们突出了这样的可维护性问题。你可能会说他们让代码闻起来更刺鼻。

Mark Seemann确定了您向我们展示的这一方法的四个个人责任。单一责任原则将规定您应该只有一个。

你可以想象将这种方法(及其所有亲属)变成更像这样的东西:

public ModuleResponse GetModules(ModuleRequest request)
{
    return _responder.CreateMappedDtoResponse(
        request,
        ModuleDao.GetModules,
        modules => new ModuleResponse {Modules = modules}));
}

现在,在这一点上,我认为你可以对这种方法进行单元测试。您几乎都在测试此方法的实现,而不是其行为。你的单元测试将测试你用给定的参数调用给定的方法,那就是它!

但即使你决定成为一个纯粹主义者和单位测试者,你真的只能进行一次单元测试,而不是之前你需要完全覆盖这种方法的四种单元测试。然后你为CreateMappedDtoResponse方法(以及它可能将其部分工作委托给它的任何方法)编写适当的单元测试,并且你已经得到了一个干燥,经过良好测试的系统,其中只有一小部分是试验。如果您更改了异常日志记录策略等常见责任,则可以在一个位置更改它,更改一个单元测试并完成。

因此,即使您的单元测试从未为您捕获过一个错误,作为一个纯粹主义者帮助您避免可维护性问题,这可能会导致您首先编写额外的代码,并且可能会重写和以后一样多的代码。当然,只有当您知道听取单元测试并相应地更改设计时才会发生这种情况。