mt2*_*t22 2 java testing junit unit-testing mocking
让我们假设我要测试这个ClassA依赖于难以实例化的Java ClassB:
public class ClassA
{
public ClassA()
{
String configFile = "config_file.xml";
// I have to pass configFile to instantiate ClassB.
// And for example if configFile does not exists in the testing machine?
// Wouldn't it be easier to have an empty constructor for classB to test ClassA?
ClassB classB = new ClassB(configFile);
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
ClassB:
class ClassB
{
ClassB(String configFile)
{
// Set up configs.
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
classB仅仅为了测试目的而在内部创建一个空构造函数是不好的做法吗?或者为此重写一个简化的模拟是否更好ClassB?
对于IoC和依赖注入来说,使用像Spring或Guice这样的东西似乎是合适的.
这种方式ClassA只会声明它"需要"一个实例ClassB,并且您的IoC容器将连接并构建所需的依赖项.
但是,如果您不想获得框架,可以通过从中提取接口契约来解决它ClassB,并ClassA依赖于此,并在其构造函数中接收该合同的实现.
例如:
interface SomeContract {
void someBehavior();
}
Run Code Online (Sandbox Code Playgroud)
有ClassB实现它:
class ClassB implements SomeContract {
{
ClassB(String configFile)
{
// Set up configs.
}
void someBehavior() {
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
并使用它,如:
public class ClassA
{
private SomeContract implementation;
public ClassA(SomeContract implementation)
{
this.implementation = implementation;
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
这样,在单元测试中,您可以传递您在测试中确定的实例,例如模拟,并且您可以相应地进行测试,而无需修改代码ClassB.
最重要的是,您应该尽量避免创建额外的构造函数,仅用于测试目的.
实际上使用无参数构造函数并使用new关键字创建依赖项会使您的类不可测试.由于您无法从构造函数中注入ClassB依赖项,因此您永远不能模拟它并隔离测试中的代码.所有的单元测试都必须测试两个类,这使得它成为一个糟糕的单元测试.相反,您应该将每个依赖项添加为构造函数参数.
这是一个更好的方法:
public class ClassA
{
// use an abstraction instead of a concrete class
private IClassB _classB;
public ClassA(IClassB classB)
{
_classB = classB;
}
}
Run Code Online (Sandbox Code Playgroud)
这样您就可以模拟IClassB,而不必担心任何ClassB实现细节.
| 归档时间: |
|
| 查看次数: |
2047 次 |
| 最近记录: |