假设有五个类:C0, C1, C2, C3, C4,它们都实现了接口I:
public interface I { public void run(); }
|
C0根据业务要求会调用C1, C2, C3, C4的run()方法(这四个类的run()方法中都会进行数据库操作):
public class C0 implements I { public void run() { I c1 = new C1(); c1.run();
//... //执行若干操作 //...
I c2 = new C2(); c2.run();
//... //执行若干操作 //...
I c3 = new C3(); c3.run();
//... //执行若干操作 //...
I c4 = new C4(); c4.run();
//... //执行若干操作 //... } }
|
在对C0的run()方法进行单元测试时发现了一个问题,C1~C4会进行数据库操作,比较费时,而且对它们的初始化都硬编码在C0的run()方法中了,所以编写C0的测试用例时无法用MockData来模拟C1~C4。
现在想到一个办法就是把C0改成下面这个样子:
public class C0 implements I {
private I c1; private I c2; private I c3; private I c4;
public C0(I argC1, I argC2, I argC3, I argC4) { c1 = argC1; c2 = argC2; c3 = argC3; c4 = argC4; }
public void run() { c1.run();
//... //执行若干操作 //...
c2.run();
//... //执行若干操作 //...
c3.run();
//... //执行若干操作 //...
c4.run();
//... //执行若干操作 //... }
public I getC1() { return c1; } public void setC1(I argC1) { c1 = argC1; }
//... //此处省略了c2~c4对应的getter/setter //...
}
|
这样的话,编写C0的测试用例时就可以使用jMock或EasyMock一类的工具来模拟C1~C4了。但如果还有C5, C6甚至是C10呢?那么在C0里可能会满是getter/setter,而且C0的构造器的参数列表也过长了。
本质上,我觉得这是个OOP的问题,也就是一个类该怎样设计,才便于对它进行隔离的单元测试,但又不致于让这个类变得很丑陋?很想看看各位有何高见?