我正在重构一个 Hibernate 映射对象Gadget
以删除getIntFieldValue
和setIntFieldValue
,并更改我的代码以从 DAO 对象中检索该值,该对象是使用 Factory
创建的,并将小工具传递给该对象。
public class GadgetPropertyAccessFactory {
public static GadgetPropertyDAO getGadgetPropertyDAO(Session dbSessn){
if(getSomeBooleanFromDB(dbSessn)) {
return new TrueImplGadgetPropertyDAO();
} else {
return new FalseImplGadgetPropertyDAO();
}
}
...
测试代码如下所示:
//this mocks a Gadget
Gadget gadget = createGadget();
//this is to be replaced
when(gadget.getIntFieldValue()).thenReturn(2);
DoerClass doerClass = new DoerClass(null, gadget);
List<Result> doerResults = doerClass.produceResults();
for (Result doerResult : doerResults) {
//...
}
DoerClass
看起来像这样
Session dbSessn;
Gadget gadget;
public DoerClass(Session dbSessn, Gadget gadget) {
this.dbSessn = dbSessn;
this.gadget = gadget;
}
public List<Result> produceResults() {
//this is to be replaced
int intFieldValue = this.gadget.getIntFieldValue()
//with
//GadgetPropertyDAO gadgPropDAO = GadgetPropertyAccessFactory.getGadgetPropertyDAO(this.dbSessn);
//int intFieldValue = gadgPropDAO.getDeviceIntFieldValue(this.gadget);
//generate List<Result> based on intFieldValue
}
我的问题是,在我能够方便地模拟getIntFieldValue
将在produceResults
返回的内容之前,但现在我使用的是静态返回的 DAO,我不知道是否可以模拟GadgetPropertyDAO.getDeviceIntFieldValue(this.gadget)
将返回的内容。
是否可以在不更改我的方法签名 (API) 的情况下进行模拟?
我同意 Tom G 的观点:Mockito 和依赖注入(可以说是 Java 本身)实际上是为实例设计的,而不是静态方法——这是利用 Java 多态优势的唯一方法。如果切换到将工厂设置为实例,它将如下所示:
public class GadgetPropertyAccessFactory {
public GadgetPropertyDAO getGadgetPropertyDAO(Session dbSessn){
if(getSomeBooleanFromDB(dbSessn)) {
return new TrueImplGadgetPropertyDAO();
} else {
return new FalseImplGadgetPropertyDAO();
}
} // ...
}
public class DoerClass {
Gadget gadget;
Session dbSessn;
// Sets default implementation. Constructor injection would also work.
GadgetPropertyAccessFactory gpaFactory = new GadgetPropertyAccessFactory();
public DoerClass(Session dbSessn, Gadget gadget) {
this.dbSessn = dbSessn;
this.gadget = gadget;
}
public List<Result> produceResults() {
GadgetPropertyDAO gadgPropDAO =
gpaFactory.getGadgetPropertyDAO(this.dbSessn);
int intFieldValue = gadgPropDAO.getDeviceIntFieldValue(this.gadget);
// ...
}
}
// in your test
DoerClass doerClass = new DoerClass(null, gadget);
GadgetPropertyAccessFactory mockFactory =
Mockito.mock(GadgetPropertyAccessFactory.class);
doerClass.gpaFactory = mockFactory;
// ...
另一种选择是忍受和管理您的测试差距:
public List<Result> produceResults() {
return produceResultsInternal(gpaFactory.getGadgetPropertyDAO(this.dbSessn));
}
/** Visible only for testing. Do not call outside of tests. */
List<Result> produceResultsInternal(GadgetPropertyDAO gadgPropDAO) {
int intFieldValue = gadgPropDAO.getDeviceIntFieldValue(this.gadget);
// ...
}
。然后,您可以使用模拟来测试produceResultsInternal
,这会让您获得 80% 的悲伤测试。