5

我有一个方法如下

public class ClientClass {

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

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

4

3 回答 3

3

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

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

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

public class ClientClass {

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

  // call me in tests
  void doSomethings(){
    // loop logic
  }
}
于 2013-09-12T18:44:12.280 回答
0

这让我有点沮丧……因为我喜欢使用控制台处理程序来启动最复杂的 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方法。

于 2018-01-18T22:19:10.023 回答
0

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

public OrderEntity createNewOrder(NewDepositRequest request, String userId) {
    return createNewOrder(request, userId);
}
于 2021-03-12T06:15:25.340 回答