【问题标题】:How do I unit test an adapter class?如何对适配器类进行单元测试?
【发布时间】:2019-12-19 22:26:32
【问题描述】:

假设我有来自第三方库的以下类:

public class ThirdPartyType { ... }

public class ThirdPartyFunction
{
    public ThirdPartyType DoSomething() { ... }
}

实现细节并不重要,它们实际上超出了我对这个第三方库的控制范围。

假设我为ThirdPartyFunction写了一个适配器类:

public class Adapter
{
    private readonly ThirdPartyFunction f;

    public Adapter()
    {
        f = new ThirdPartyFunction();
    }

    public string DoSomething()
    {
        var result = f.DoSomething();

        // Convert to a type that my clients can understand
        return Convert(result);
    }

    private string Convert(ThirdPartyType value)
    {
        // Complex conversion from ThirdPartyType to string
        // (how do I test this private method?)
        ...
    }
}

如何测试我的Convert(ThirdPartyType) 实现是否正确?只有Adapter 类需要它,这就是它是私有方法的原因。

【问题讨论】:

  • 验证DoSomething,如果正确完成应该验证Convert...您通常不验证私有方法,但如果将其标记为内部,则可以将其公开给测试库。
  • @RonBeyer 我同意验证 DoSomething 将负责转换。但是,第三方库已经过非常彻底的测试(假设有数千次测试),我不想再重复所有这些测试。 “内部”的想法是可行的。

标签: c# unit-testing nunit xunit


【解决方案1】:

我建议将代码提取到单独的类中,然后测试该类。尽管它仅由 Adapter 使用,但适配器也不应负责进行转换(符合单一职责原则)。

通过将其提取出来,您可以独立于第三方代码来测试转换器。

如果转换器不需要任何状态,您也可以将其设为静态类,然后直接在适配器中引用它,而无需使用依赖注入进行注册。

如果您考虑一下,适配器不需要测试(因为它只是一个包装器)但转换器需要 - 因此将其提取到另一个类以允许对其进行测试是有意义的,即使它确实意味着另一个代码中的类。

此外,将转换器提取到单独的类意味着如果ThirdPartyTypestring 的格式发生更改,那么您可以在不影响Adapter 实现的情况下进行更改。

【讨论】:

    【解决方案2】:

    如果您更改您的 Adapter 类以允许将 ThirdPartyFunction f 传递给它,那么您可以在您的测试类中使用它的模拟版本。这将允许您测试转换功能。

    由于我不熟悉该语言,我不确定确切的语法,但我会尝试一下:

    public class Adapter
    {
      private readonly ThirdPartyFunction f;
    
      // pass the function to the constructor when creating the adapter
      public Adapter(ThirdPartyFunction inputF)
        {
          f = inputF;
        }
    
      public string DoSomething()
      {
        var result = f.DoSomething();
    
        // Convert to a type that my clients can understand
        return Convert(result);
      }
    
      private string Convert(ThirdPartyType value)
      {
        // Complex conversion from ThirdPartyType to string
        // (how do I test this private method?)
        ...
      }
    }
    

    在您的实际实现中,当您创建new Adapter 时,您可以将new ThirdPartyFunction 传递给它。

    在您的测试实现中,您可以将 ThirdPartyFunction 的模拟版本传递给它,它会返回一个固定值进行测试。也许像:

    class MockThirdPartyFunction extends ThirdPartyFunction
    {
      private ThirdPartyType testData;
    
      public MockThirdPartyFunction(ThirdPartyType data)
      {
        testData = data;
      }
    
      override public ThirdPartyType DoSomething() 
      {
        // return a fixed third party type passed in on mock creation
        return testData
      }
    }
    

    您使用模拟值创建测试适配器,您可以在其中设置要测试的特定ThirdPartyType。然后在您的测试中,当您在Adapter 上调用DoSomething 时,您正在控制转换函数的输入,并且可以查看输出并相应地与预期结果进行比较。

    【讨论】:

      猜你喜欢
      • 2014-01-28
      • 1970-01-01
      • 1970-01-01
      • 2011-09-17
      • 1970-01-01
      • 2011-12-19
      • 2014-10-08
      • 2011-03-24
      • 2012-02-29
      相关资源
      最近更新 更多