【问题标题】:How to mock Objects that are not passed as arguments如何模拟未作为参数传递的对象
【发布时间】:2013-03-14 10:32:32
【问题描述】:

想象下面的类

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 或任何其他框架返回的内容?

【问题讨论】:

标签: java testing mocking mockito


【解决方案1】:

如果可用,您可以使用 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 发布的可能重复的链接。 虽然这种做法通常是糟糕设计的标志,但如果你能把它拿出来,我会的。

【讨论】:

    【解决方案2】:

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

    但是,如果您经常做这种事情,我建议您使用 PowerMock(与 Mockito 结合使用)或 JMockIt 来实现这一点。两者都允许您模拟构造函数、静态变量、最终字段……简而言之,几乎任何东西。对遗留代码非常有用。

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

    【讨论】:

      【解决方案3】:

      作为一种快速解决方法,我通常将电话转至new

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

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

      【讨论】:

        【解决方案4】:

        这是一个 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...
            }};
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-14
          • 1970-01-01
          • 2018-03-07
          • 2019-10-19
          • 2019-03-11
          • 1970-01-01
          相关资源
          最近更新 更多