需要帮助确定要编写的单元测试

Son*_*ate 5 c# testing tdd unit-testing

我有以下方法,我正在寻找有效的单元测试,也给我很好的代码路径覆盖:

public TheResponse DoSomething(TheRequest request)
{
    if (request == null)
        throw new ArgumentNullException("request");

    BeginRequest(request);

    try
    {
        var result = Service.DoTheWork(request.Data);

        var response = Mapper.Map<TheResult, TheResponse>(result);

        return response;
    }
    catch (Exception ex)
    {
        Logger.LogError("This method failed.", ex);

        throw;
    }
    finally
    {
        EndRequest();
    }
}
Run Code Online (Sandbox Code Playgroud)

该方法使用的Service和Logger对象被注入类构造函数(未显示).BeginRequest和EndRequest在基类(未示出)中实现.Mapper是用于对象到对象映射的AutoMapper类.

我的问题是为这样的方法编写单元测试的好的,有效的方法是什么,它还提供完整的(或有意义的)代码覆盖?

我是一对一测试主体的信徒,并且在VS-Test中使用Moq作为一个模拟框架(尽管我并没有因为这个问题而挂断了这个部分).虽然有些测试(例如确保传递null导致例外)很明显,但我发现自己想知道其他想到的是否有意义; 特别是当他们以不同的方式行使相同的代码时.

k.m*_*k.m 2

从您的帖子/评论来看,您似乎已经知道应该编写哪些测试,并且它与我在第一眼看到您的代码后测试的内容非常匹配。首先有一些明显的事情:

  • 空参数异常检查
  • 模拟服务和记录器以检查是否使用正确的数据调用它们
  • 存根映射器(以及可能的服务)检查是否实际返回了正确的结果

现在,困难的部分。根据您的基类是否是您可以访问的内容(例如,可以轻松更改它),您可以尝试称为Extract & Override的方法:

  1. 在基类中将 BeginRequest/EndRequest 标记为虚拟
  2. 在派生类中对它们不执行任何操作
  3. 引入从您要测试的类派生的新的、可测试的类;重写基类的方法(BeginRequest/EndRequest),使它们例如。更改一些您稍后可以轻松验证的内部值

代码可能看起来或多或少像这样:

Base 
{
    protected virtual void BeginRequest(TheRequest request) { ... }
    protected virtual void EndRequest() { ... }
}

Derived : Base // class you want to test
{
    // your regular implementation goes here
    // virtual methods remain the same
}

TestableDerived : Derived // class you'll actually test
{
    // here you could for example expose some properties 
    // determining whether Begin/EndRequest were actually called,
    // calls were made in correct order and so on - whatever makes
    // it easier to verify later

    protected override void BeginRequest(TheRequest request) { ... }
    protected override void EndRequest() { ... }  
}
Run Code Online (Sandbox Code Playgroud)

您可以在《单元测试的艺术》一书以及《有效处理遗留代码》中找到有关此技术的更多信息。尽管我相信可能有更优雅的解决方案,但这个解决方案应该使您能够测试流程并验证 DoSomething 方法内交互的一般正确性。

当您无权访问基类并且无法修改其代码时,当然会出现问题。不幸的是,我没有针对这种情况的“书外”解决方案,但也许您可以在 Derived 中围绕 Begin/EndRequest 创建虚拟包装器,并且仍然使用提取和覆盖 TestableDerived。