You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中测试方法重试逻辑的方式是否正确?还有其他方案吗?

Testing a Method that Retries Another Method Call

I need to test a method that calls another method multiple times (with retry logic on exception). Here's the sample production code:

class Sample{
    OtherClass otherClass;
    public OutputPoJo callABCMultipleTImes(){
        OutputPoJo outputPojo;
        try{
            outputPojo = otherClass.callABC();
        } catch(RuntimeException ex){
            //Retrying call one more time
            outputPojo = otherClass.callABC();
        }
        return outputPojo;
    }
}

I've written the following test code, which works correctly in different scenarios:

public void testCallABCMultipleTImes(){
    when(otherClass.callABC())
        .thenThrow(new RuntimeException("First try failed."))
        .thenReturn(new OutputPOJO());
    mockedSampleClass.callABCMultipleTImes();
    Mockito.verify(otherClass,Mockito.times(2)).callABC();
}

I'm verifying that callABC is called twice to confirm that the logic (first call throws exception, second call returns success) works. Is this testing approach correct? Are there other testing solutions?


Great question! Your current test approach is absolutely correct for validating the retry behavior in the failure-then-success scenario. Let's break this down and explore other useful testing strategies:

1. Why your current test works

You're using Mockito's sequential stubbing (thenThrow().thenReturn()) to simulate the first failure and second success, then verifying the call count. This directly validates that your retry logic triggers as expected—when the first callABC throws an exception, the code falls into the catch block and makes a second call. This is a solid core test for this scenario.

2. Additional test scenarios you should cover

Your current test covers one critical path, but there are other cases worth validating to ensure full coverage:

a. Test the happy path (no retry needed)

Verify that when callABC succeeds on the first try, the method doesn't make an unnecessary second call, and returns the correct value:

@Test
public void testCallABCMultipleTimes_NoRetry() {
    OutputPOJO expectedOutput = new OutputPOJO();
    when(otherClass.callABC()).thenReturn(expectedOutput);
    
    OutputPOJO actualOutput = mockedSampleClass.callABCMultipleTImes();
    
    Mockito.verify(otherClass, Mockito.times(1)).callABC();
    assertEquals(expectedOutput, actualOutput); // Confirm we get the successful result
}

b. Validate the returned value in the retry scenario

Your current test checks the call count, but it's also important to confirm that the method returns the successful result from the second call (not some default or invalid value):

@Test
public void testCallABCMultipleTimes_ReturnsSuccessOnRetry() {
    OutputPOJO expectedOutput = new OutputPOJO();
    when(otherClass.callABC())
        .thenThrow(new RuntimeException("First try failed."))
        .thenReturn(expectedOutput);
    
    OutputPOJO actualOutput = mockedSampleClass.callABCMultipleTImes();
    
    Mockito.verify(otherClass, Mockito.times(2)).callABC();
    assertEquals(expectedOutput, actualOutput); // Ensure the retry returns the correct POJO
}

c. Test what happens if both calls fail

Right now, your production code will propagate the exception from the second callABC call. You should test this behavior to confirm there's no infinite loop or unexpected handling:

@Test(expected = RuntimeException.class)
public void testCallABCMultipleTimes_BothCallsFail() {
    RuntimeException testException = new RuntimeException("All tries failed.");
    when(otherClass.callABC()).thenThrow(testException);
    
    mockedSampleClass.callABCMultipleTImes();
    
    Mockito.verify(otherClass, Mockito.times(2)).callABC();
    // The test expects the exception to be thrown, validating no extra retries
}

3. Alternative testing approaches

If you want to make your tests more expressive or prepare for future changes, consider these options:

a. Using Mockito's InOrder to verify call sequence

While your count check works, InOrder can explicitly confirm that the calls happen in the expected order—useful if you ever add more complex retry logic (like conditional retries):

@Test
public void testCallABCMultipleTimes_Sequence() {
    when(otherClass.callABC())
        .thenThrow(new RuntimeException("First try failed."))
        .thenReturn(new OutputPOJO());
    
    mockedSampleClass.callABCMultipleTImes();
    
    InOrder inOrder = inOrder(otherClass);
    inOrder.verify(otherClass).callABC(); // First failed call
    inOrder.verify(otherClass).callABC(); // Second successful call
}

b. Extract retry logic for independent testing

If you plan to expand the retry logic (e.g., adding more retries, delays, or retry conditions), extract it into a separate helper class/method. This lets you test the retry logic in isolation, without coupling it to the Sample class's other responsibilities.

内容的提问来源于stack exchange,提问作者tv1902

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 09:23:13