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

时间:2014-12-18 17:37:52

标签: java mockito

假设我有一个这样的类:

public class MyClass {

    Dao dao;

    public String myMethod(Dao d) {

        dao = d;

        String result = dao.query();

        return result;
    } 
}

我想用mockito测试它。所以我创建了一个模拟对象,并调用方法以这种方式进行测试:

Dao mock = Mockito.mock(Dao.class);

Mockito.when(mock.myMethod()).thenReturn("ok");

new MyClass().myMethod(mock);

但是,假设我有一个类似的课程:

public class MyClass {

    Dao dao = new Dao();

    public String myMethod() {

        String result = dao.query();

        return result;
    } 
}

现在我无法将我的模拟作为参数传递,所以我将如何测试我的方法?有人可以举个例子吗?

2 个答案:

答案 0 :(得分:10)

从根本上说,您尝试使用替代实现替换私有字段,这意味着您违反了封装。您唯一的另一个选择是重新构建类或方法,使其更好地设计用于测试。

评论中有很多简短的答案,所以我在这里汇总它们(并添加我自己的几个)作为社区Wiki。 如果您有任何其他选择,请随时在此处添加。

重组班级

  • 为相关字段创建一个setter,或放宽字段的可见性。
  • 创建一个依赖注入的覆盖或静态方法,它接受DAO,并使公共实例方法委托给它。而是测试更灵活的方法。

    public String myMethod() { return myMethod(dao); }
    String myMethod(Dao dao) { /* real implementation here */ }
    
  • 添加构造函数重载或静态工厂方法,以替换私有字段以进行测试。
  • 完全构建dependency injection的类。 (Sotirios DelimanolisEJK

请注意,如果将测试放在同一个Java包中(可能在单独的源代码树中),其中一些可以是package-private进行测试。在所有情况下,良好的名称和文档都有助于明确您的意图。

违反封装

答案 1 :(得分:2)

这是怎么回事?

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...
    } 
}

编辑:正如评论中所述,这假定您不会更改dao字段的名称。然后获取所有字段Field[] fields = myClass.getClass().getDeclaredFields();并迭代它们,获得Dao类型的字段可能是个好主意。然后按上述步骤进行。这样,您的测试就不再依赖于您的字段名称了。