当我们不能将模拟对象传递给类的实例时如何使用Mockito

假设我有这样的一个类:

public class MyClass { Dao dao; public String myMethod(Dao d) { dao = d; String result = dao.query(); return result; } } 

我想用mockito来testing它。 所以我创build一个模拟对象,然后我调用这个方法来testing:

 Dao mock = Mockito.mock(Dao.class); Mockito.when(mock.myMethod()).thenReturn("ok"); new MyClass().myMethod(mock); 

但是,假设我有这样一个class级:

 public class MyClass { Dao dao = new Dao(); public String myMethod() { String result = dao.query(); return result; } } 

现在我不能把我的模拟作为一个论点,所以我要如何testing我的方法? 有人可以举个例子吗?

从根本上说,你正试图用一个替代实现replace一个私有字段,这意味着你会违反封装。 你唯一的select是重构类或方法,使其更好地devise用于testing。

在评论中有很多简短的答案,所以我把它们聚集在这里(并且添加一些我自己的)作为社区Wiki。 如果您有其他方法,请随时在这里添加。

重组class级

  • 为有问题的领域创build一个setter,或放松领域的知名度。
  • 创build一个dependency injection覆盖或采用DAO的静态方法,并将公共实例方法委托给它。 testing更灵活的方法。

     public String myMethod() { return myMethod(dao); } String myMethod(Dao dao) { /* real implementation here */ } 
  • 为了testing的目的,添加一个构造函数重载或静态工厂方法来replace私有字段。
  • 充分构builddependency injection的类。 ( Sotirios Delimanolis , EJK )

请注意,如果您将testing放在同一个Java包(可能位于单独的源代码树中),那么其中一些可以是专用于testing的包。 在所有情况下,好的名字和文件都有助于使你的意图清晰。

违反封装

  • 使用reflection设置类中的私有字段。 (金iko子 – 见答案 )
  • 使用PowerMockito来replace你的select模拟Dao构造函数。 ( 戴夫牛顿 )

这个怎么样?

 public class MyClassTest { MyClass myClass = new MyClass(); Dao dao = Mockito.mock(Dao.class); public void testMyMethod() { Field field = myClass.getClass().getDeclaredField("dao"); field.setAccessible(true); field.set(myClass, dao); //Do the test... } } 

编辑:正如在评论中提到的,这假定你不改变道场的名称。 这可能是一个好主意,然后获取所有的字段, Field[] fields = myClass.getClass().getDeclaredFields(); 并遍历它们,得到Daotypes的字段。 然后继续如上。 这样,你的testing不再依赖于你的领域的名字。