【问题标题】:Mockito mock a method with infinite loopMockito 模拟具有无限循环的方法
【发布时间】:2013-09-17 06:53:32
【问题描述】:

我有一个方法如下

public class ClientClass {

    public void clientMethod() {
        while(true){
           doSomethings.....
       }
    }
}

我正在尝试使用 mockito 进行测试。我能够调用clientMethod,但是由于clientMethod中有一个while(true),所以调用永远不会返回,我也永远不会到达我的assert语句,这些语句(当然)在clientMethod()调用之后发生。 有没有办法在我的测试用例的一次循环迭代后停止循环?

【问题讨论】:

  • 当代码在生产环境中运行时,程序如何跳出循环?你能模拟出同样的情况吗?

标签: loops testing mocking mockito infinite


【解决方案1】:

从技术上讲,您不能在不从内部抛出异常的情况下打破测试中的无限循环。如果您可以模拟循环中的某些内容,那么它可能会为您产生异常。

当您发现自己处于这种情况下,当需要采用笨拙的变通方法进行测试时,是时候停下来考虑一下设计了。不可测试的代码通常难以维护,而且不是很容易解释。所以我的建议是摆脱无限循环并引入适当的循环条件。毕竟,没有应用程序会永远存在。

如果您仍然相信无限循环是最好的方法,那么您可以执行轻微的分解以使事情更可测试:

public class ClientClass {

  // call me in production code
  public void clientMethod() {
    while(true){
        doSomethings();
    }
  }

  // call me in tests
  void doSomethings(){
    // loop logic
  }
}

【讨论】:

    【解决方案2】:

    这让我有点沮丧...因为我喜欢使用控制台处理程序来启动最复杂的 GUI 应用程序。

    我在这里使用的语言是 Groovy,它是 Java 的一种奇妙扩展,可以与普通的旧 Java 混合使用。

    class ConsoleHandler {
    
        def loopCount = 0
        def maxLoopCount = 100000
    
        void loop() {
            while( ! endConditionMet() ){
                // ... do something
            }
        }
    
        boolean endConditionMet() {
            loopCount++
            loopCount > maxLoopCount // NB no "return" needed!
        }
    
        static void main( args ) {
            new ConsoleHandler().loop()
        }
    }
    

    ...在测试类中(也在 Groovy 中)然后你可以去

    import org.junit.contrib.java.lang.system.SystemOutRule
    import org.junit.contrib.java.lang.system.
        TextFromStandardInputStream.emptyStandardInputStream
    import static org.assertj.core.api.Assertions.assertThat
    import org.junit.Rule
    import static org.mockito.Mockito.*
    
    class XXTests {
        @Rule
        public SystemOutRule systemOutRule = new SystemOutRule().enableLog()
        @Rule
        public TextFromStandardInputStream systemInMock = emptyStandardInputStream()
        ConsoleHandler spyConsoleHandler = spy(new ConsoleHandler())
    
        @Test
        void readInShouldFollowedByAnother()  {
            spyConsoleHandler.setMaxLoopCount 10
            systemInMock.provideLines( 'blah', 'boggle')
            spyConsoleHandler.loop()
            assertThat( systemOutRule.getLog() ).containsIgnoringCase( 'blah' )
            assertThat( systemOutRule.getLog() ).containsIgnoringCase( 'boggle' )
    

    这里发生的美妙之处在于,只需声明maxLoopCount,该语言就会自动创建两个方法:getMaxLoopCountsetMaxLoopCount(您甚至不必费心括号)。

    当然,下一个测试是“如果用户输入 Q,则必须退出循环”或其他什么...但是关于 TDD 的要点是您希望它最初失败!

    如果必须的话,可以使用普通的旧 Java 复制上述内容:当然,您必须创建自己的 setXXX 方法。

    【讨论】:

      【解决方案3】:

      我陷入了困境,因为我错误地从方法内部调用了相同的方法。

      public OrderEntity createNewOrder(NewDepositRequest request, String userId) {
          return createNewOrder(request, userId);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-11
        • 1970-01-01
        • 2015-12-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多