【问题标题】:How can I mock methods of @InjectMocks class?如何模拟 @InjectMocks 类的方法?
【发布时间】:2015-08-26 18:27:14
【问题描述】:

例如我有处理程序:

@Component
public class MyHandler {

  @AutoWired
  private MyDependency myDependency;

  public int someMethod() {
    ...
    return anotherMethod();
  }

  public int anotherMethod() {...}
}

为了测试它,我想写这样的东西:

@RunWith(MockitoJUnitRunner.class}
class MyHandlerTest {

  @InjectMocks
  private MyHandler myHandler;

  @Mock
  private MyDependency myDependency;

  @Test
  public void testSomeMethod() {
    when(myHandler.anotherMethod()).thenReturn(1);
    assertEquals(myHandler.someMethod() == 1);
  }
}

但每当我尝试模拟它时,它实际上都会调用anotherMethod()。我应该如何处理 myHandler 来模拟它的方法?

【问题讨论】:

  • 如果你想测试 MyHandler,你不应该模拟它自己的方法(因为你想测试你的处理程序,而不是模拟)。您是否需要这样做的具体原因?

标签: java unit-testing mocking mockito


【解决方案1】:

在您的代码中,您根本没有测试 MyHandler。你不想模拟你正在测试的东西,你想调用它的实际方法。如果 MyHandler 有依赖项,则模拟它们。

类似这样的:

public interface MyDependency {
  public int otherMethod();
}

public class MyHandler {
  @AutoWired
  private MyDependency myDependency;

  public void someMethod() {
    myDependency.otherMethod();
  }
}

在测试中:

private MyDependency mockDependency;
private MyHandler realHandler;

@Before
public void setup() {
   mockDependency = Mockito.mock(MyDependency.class);
   realHandler = new MyHandler();
   realhandler.setDependency(mockDependency); //but you might Springify this 
}

@Test
public void testSomeMethod() {

  //specify behaviour of mock
  when(mockDependency.otherMethod()).thenReturn(1);

  //really call the method under test
  realHandler.someMethod();
}

重点是真正调用被测方法,但模拟它们可能具有的任何依赖项(例如调用其他类的方法)

如果这些其他类是您的应用程序的一部分,那么它们会有自己的单元测试。

注意上面的代码可以用更多的注释来缩短,但为了解释起见,我想让它更明确(而且我不记得注释是什么了:))

【讨论】:

  • 在使用 Spring IOC 时创建实例。你没有从春季国际奥委会中受益。假设我是否必须注入另一个服务。我不能这样做。我必须创建一个实例。
  • 小心这种答案,有很多场景我们不想测试整个班级,而只是测试一部分。例如,我有一个从外部框架继承的类,很难在模拟中初始化,具有非常复杂的上下文。初始化它很痛苦,但也没有用只测试我的函数,它使用了这个上下文的一小部分。
【解决方案2】:

首先,mock MyHandler 方法的原因可能如下:我们已经测试了anotherMethod(),它的逻辑很复杂,如果可以的话,为什么我们需要再次测试它(就像someMethod() 的一部分)只是 verify 它在打电话吗?
我们可以通过:

@RunWith(MockitoJUnitRunner.class)
class MyHandlerTest {

  @Spy  
  @InjectMocks  
  private MyHandler myHandler;  

  @Mock  
  private MyDependency myDependency;  

  @Test  
  public void testSomeMethod() {  
    doReturn(1).when(myHandler).anotherMethod();  
    assertEquals(myHandler.someMethod() == 1);  
    verify(myHandler, times(1)).anotherMethod();  
  }  
}  

注意:如果是'spying'对象,我们需要使用doReturn而不是thenReturn(小解释是here

【讨论】:

  • 如果你同时使用 Spy 和 InjectMocks 注释,它不会注入任何东西
  • @ildarishalin 我刚刚尝试使用 junit 4.12 和 mockito-core 2.15,一切正常
  • 我不确定@Spy@InjectMocks应该一起使用-> stackoverflow.com/questions/38567326/…
  • @ildarishalin 也许你被both、模拟方法真正的方法所愚弄了。为避免这种情况,您可以在 doReturn()...when() 中使用“mockito old style”。另请参阅javadoc.io/static/org.mockito/mockito-core/3.3.1/org/mockito/… 下的问题
  • 第一行@RunWith(MockitoJUnitRunner.class}请把最后一个字符'}'换成')'
【解决方案3】:

以上所有答案都非常好,可能有用,因此请确保在继续阅读我的帖子之前先学习并理解这些原则。

在我的情况下,上述建议都不起作用。经过相当长的调试后,我将发布对我有帮助的内容。

如果您想从测试类调用方法,则需要 @Spy 注释以及 @InjectMocks(或 Mockito.spy(XXX) 调用或课程)

有趣的是,这些注释的顺序很重要@Spy 注释必须在 @InjectMocks 注释之前。

不会工作

...

@InjectMocks
@Spy
private TestedObject instance

...

会起作用

...

@Spy
@InjectMocks
private TestedObject instance

...

【讨论】:

    猜你喜欢
    • 2020-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    相关资源
    最近更新 更多