如何对适配器 class 进行单元测试?

How do I unit test an adapter class?

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

public class ThirdPartyType { ... }

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

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

假设我为 ThirdPartyFunction:

写了一个适配器 class
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 class 需要它,这就是为什么它是一个私有方法。

我建议将代码提取到单独的 class,然后测试 class。虽然它只被这个 Adapter 使用,但适配器也不应该负责进行转换(与单一职责原则保持一致)。

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

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

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

此外,将转换器提取到单独的 class 意味着如果 ThirdPartyTypestring 的格式发生变化,那么您可以在不影响 Adapter 实施。

如果您更改适配器 class 以允许将 ThirdPartyFunction f 传递给它,那么您可以在测试中使用它的模拟版本 class。这将允许您测试 Convert 函数。

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

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 的模拟版本传递给它,其中 returns 是用于测试的固定值。也许喜欢:

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 时,您正在控制 Convert 函数的输入并且可以看到输出并相应地与预期结果进行比较。