如何对适配器 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 意味着如果 ThirdPartyType
或 string
的格式发生变化,那么您可以在不影响 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 函数的输入并且可以看到输出并相应地与预期结果进行比较。
假设我有来自第三方库的以下 classes:
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
class 需要它,这就是为什么它是一个私有方法。
我建议将代码提取到单独的 class,然后测试 class。虽然它只被这个 Adapter
使用,但适配器也不应该负责进行转换(与单一职责原则保持一致)。
通过将其提取出来,您可以独立于第三方代码测试转换器。
如果转换器不需要任何状态,您也可以将其设为静态 class,然后直接在您的适配器中引用它,而无需使用依赖注入进行注册。
如果你考虑一下,适配器不需要测试(因为它只是一个包装器)但转换器需要 - 所以将它提取到另一个 class 允许它进行测试是有意义的,即使它确实意味着代码中的另一个 class。
此外,将转换器提取到单独的 class 意味着如果 ThirdPartyType
或 string
的格式发生变化,那么您可以在不影响 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 函数的输入并且可以看到输出并相应地与预期结果进行比较。