如何模拟未作为参数传递的对象

时间:2013-03-14 10:32:32

标签: java testing mocking mockito

想象一下以下的课程

public class ClassToBeTested{

  private AnotherClass otherClass;

  public void methodToBeTested(){
     otherClass = new AnotherClass();
     String temp = otherClass.someMethod()

    // ...some other code that depends on temp

  }

}

现在,如果methodToBeTested设计为接受AnotherClass的实例,我可以轻松创建AnotherClass的模拟,并告诉Mockito在someMethod()时返回值叫做。但是,由于上面的代码是AFAIK设计的,因此无法模拟AnotherClass,测试此方法将取决于someMethod()返回的内容。

无论如何我可以测试上面的代码,而不依赖于someMethod()使用Mockito或任何其他框架返回的内容吗?

4 个答案:

答案 0 :(得分:3)

如果可用,您可以使用Spring ReflectionTestUtils setField方法:

http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/util/ReflectionTestUtils.html#setField%28java.lang.Object,%20java.lang.String,%20java.lang.Object%29

如果没有使用反射写出你自己的非常简单,这里有一些信息:

http://www.java2s.com/Code/Java/Reflection/Setprivatefieldvalue.htm

如下所示,您需要额外的错误处理才能使其正常工作:

public void setField(Object obj, String fieldName, Object value) {
    Field f = obj.getDeclaredField(fieldName);
    f.setAccessible(true);
    f.set(obj, value);
}

然后可以这样调用:

setField(objUnderTest, "fieldToSet", mockObject); 

修改

我刚刚注意到你在方法中实例化它。如果这是绝对必要的,那么你应该遵循cyroxx发布的可能的重复链接。 虽然这种做法往往是糟糕设计的标志,所以如果你能把它拿出来,我会的。

答案 1 :(得分:2)

按照其他答案中的建议通过反射设置字段将起作用。

但如果你经常这样做,我会推荐PowerMock(与Mockito合作)或JMockIt来实现这一目标。两者都允许你模拟构造函数,静态函数,最终字段......简而言之,几乎任何东西。对遗留代码非常有用。

但是,当您编写新代码并且您的类依赖于您希望以这种方式隔离的另一个类时,您应该考虑更改设计,以便将另一个对象传递到您的类而不是被它实例化。搜索“依赖注入”,你会发现很多......

答案 2 :(得分:1)

作为一个快速解决方案,我通常将调用包裹到new

protected newAnotherClass() { return new AnotherClass(); }

这样,我可以从单元测试中覆盖这个方法。它很脏但很快: - )

答案 3 :(得分:0)

这是一个JMockit测试,可以非常简单地完成您想要的测试:

@Test
public void testTheMethodToBeTested(@Mocked final AnotherClass dep)
{
    new NonStrictExpectations() {{ dep.someMethod(); result = "whatever"; }};

    new ClassToBeTested().methodToBeTested();

    new Verifications() {{
        // verify other calls to `dep`, if applicable...
    }};
}