Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用静态工厂方法创建的对象的模拟行为_Java_Mockito - Fatal编程技术网

Java 使用静态工厂方法创建的对象的模拟行为

Java 使用静态工厂方法创建的对象的模拟行为,java,mockito,Java,Mockito,我正在重构一个Hibernate映射对象Gadget以删除getIntFieldValue和setIntFieldValue,并更改代码以从DAO对象检索该值,DAO对象是使用工厂创建的,并向其传递了一个Gadget public class GadgetPropertyAccessFactory { public static GadgetPropertyDAO getGadgetPropertyDAO(Session dbSessn){ if(getSomeBoo

我正在重构一个Hibernate映射对象
Gadget
以删除
getIntFieldValue
setIntFieldValue
,并更改代码以从DAO对象检索该值,DAO对象是使用
工厂创建的,并向其传递了一个Gadget

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) {
    //...
}
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;
// ...
我的问题是,在我能够方便地模拟
getIntFieldValue
将在
produceResults
中返回的内容之前,但现在我使用的是静态返回的DAO,我不知道是否可以模拟
GadgetPropertyDAO.getDeviceInFieldValue(this.gadget)
将返回的内容


在不改变我的方法签名(API)的情况下,模拟是可能的吗?

我同意Tom G的观点:模拟和依赖注入(可以说是Java本身)实际上是为实例设计的,而不是为静态方法设计的,这是利用Java多态性优势的唯一方法。如果您切换到将工厂作为实例,它将如下所示:

//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) {
    //...
}
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;
// ...
公共类GadgetPropertyAccessFactory{
公共GadgetPropertyDAO getGadgetPropertyDAO(会话dbSessn){
if(getSomeBooleanFromDB(dbessn)){
返回新的TrueImplGadgetPropertyDAO();
}否则{
返回新的FalseImpledGadgetPropertyDao();
}
} // ...
}
公共类DoerClass{
小玩意;
会话dbSessn;
//设置默认实现。构造函数注入也可以工作。
GadgetPropertyAccessFactory gpaFactory=新的GadgetPropertyAccessFactory();
public DoerClass(会话dbessn,Gadget Gadget){
this.dbSessn=dbSessn;
this.gadget=gadget;
}
公开列表生产结果(){
GadgetPropertyDAO gadgPropDAO=
gpaFactory.getGadgetPropertyDAO(this.dbessn);
int intFieldValue=gadgPropDAO.getDeviceIntFieldValue(this.gadget);
// ...
}
}
//在你的测试中
DoerClass DoerClass=新DoerClass(空,小工具);
GadgetPropertyAccessFactory模拟工厂=
Mockito.mock(GadgetPropertyAccessFactory.class);
doerClass.gpaFactory=模拟工厂;
// ...
另一种选择是接受并管理您的测试差距:

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);
  // ...
}
公共列表produceResults(){
返回ProduceResultInternal(gpaFactory.getGadgetPropertyDAO(this.dbessn));
}
/**仅在测试时可见。不要在测试之外调用*/
列出产品结果内部(GadgetPropertyDAO gadgPropDAO){
int intFieldValue=gadgPropDAO.getDeviceIntFieldValue(this.gadget);
// ...
}

…然后,您可以使用模拟来测试内部的
produceResultsInternal
,这会让您在20%的痛苦中得到80%的测试。

听起来您的设计在倒退——您的
DoerClass
不应该负责从DAO检索小工具。它不是在检索小工具。小工具通过构造函数传递给它。produceResults需要数据库中其他地方的重构字段,这些字段现在通过分解的DAOMy MIRST访问——不过,像这样检索DAO是这里的问题。我的建议是采用更具依赖注入风格的方法,并提供
GadgetPropertyDAO
作为构造函数参数。然后可以模拟
getDeviceIntFieldValue
调用。尝试将PowerMock与Mockito结合使用。我认为您可以模拟
GadgetPropertyAccessFactory.getGadgetPropertyDAO(this.dbessn)
并返回一个模拟的
GadgetPropertyDAO
。有关详细信息,请选中此项: