如何为具有重试逻辑的方法编写junit测试用例



retry方法精确地查找特定文件的文件夹,并返回文件(如果存在(。它的最大重试次数为3,并且在两次重试之间休眠1分钟。如果在最大重试后文件不存在,它会抛出一些异常

这种方法很像

File getFile(int retryCount){
File file;
file =getFilefromLocation();
if(file!=null) return file
if(file==null and retryCount>0)
Thread.sleep(1)
--retryCount;
File filePicked =getFile( retryCount)
}
else return null;
}

一种可能的方法是将检查文件是否存在的部分分解到自己的对象中,并模拟该对象。

我会配置重试时间,并将其设置为1秒进行测试。您可以在文件已经存在、从未存在的情况下进行测试,也可以将其作为后台线程添加。大约需要5秒钟。

我也会更频繁地考虑更短的重试时间,例如每1秒120次尝试,而不是每分钟3次。

我会尝试给出一些指针。

1( 在这里,我不会模拟整个逻辑来检查文件的存在,因为它是被测试方法行为的一部分
您想要模拟的是实际尝试检索文件的部分,即调用getFilefromLocation()的部分。

2( 在两次重试之间使用短延迟是一个想法,但这足以使您的测试变得健壮吗
不是因为您还必须断言Thread.sleep()已被调用并且具有预期值。在单元测试中不检查这一点意味着任何人都可以在getFile()方法中删除Thread.sleep(),测试仍然会通过。你真的不希望这样
请注意,您不能轻易嘲笑它:它是static。您应该将此语句移动到可以模拟的DelayService中。

3( 实际上,您参数化了retryCount。在编写单元测试时,您希望根据您的需求验证组件的行为。因此,您还应该确保依赖于getFile(int retryCount)的类有效地传递期望的参数:3
此外,如果您不想允许超过某个重试次数,您还必须在方法中添加此检查,并在单元测试中断言此规则。

根据前两点,您的实际代码可以重构为:

private FileLocator fileLocator; // added dependency
private DelayService delayService; // added dependency
//  constructor to set these dependencies
public MyService(FileLocator fileLocator, DelayService delayService){
...
}
File getFile(int retryCount){
File file;
file = fileLocator.getFilefromLocation(); // -> change here
if(file!=null) return file
if(file==null and retryCount>0){
delayService.waitFor(); // -> other change here
--retryCount;
File filePicked = getFile(retryCount)
}
else return null;
}

关于单元测试部分,您可以使用Mockito来模拟并混合"简单"单元测试和参数化测试,因为有些场景具有类似的行为,实际重试次数也不同
例如,重试0、1、2和3次并找到文件是4种可以参数化的情况
相反,找不到文件不需要参数化,因为应该进行所有重试来验证行为。

这里有一个依赖JUnit5和Mockito(未测试(的代码示例,您可以根据实际代码进行调整。我刚刚用参数化测试做了说明。其他测试用例的实现不应该更复杂。

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.junit.jupiter.api.Assertions;
import org.mockito.Mockito;
import org.mockito.Mock;
private static final long EXPECTED_DELAY_MN = 1; 
private static final long RETRY_COUNT = 3; 
@Mock
FileLocator fileLocatorMock;
@Mock
private DelayService delayServiceMock;

MyServiceTest myServiceTest;
public MyServiceTest(){
myServiceTest = new MyServiceTest(fileLocatorMock, delayServiceMock);
}
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2, 3 })
public void getFileThatFailsMultipleTimeAndSuccess(int nbRetryRequired){    
// failing find
for (int i=0; i < nbRetryRequired; i++) {
Mockito.when(fileLocatorMock.getFilefromLocation(...)).thenReturn(null);
}
// successful find
File fileByMock = new File(...); //fake file
Mockito.when(fileLocatorMock.getFilefromLocation(...)).thenReturn(fileByock);
File actualFile = myServiceTest.getFile(RETRY_COUNT);
// assertions
Mockito.verify(delayServiceMock, Mockito.times(nbRetryRequired)) 
.waitFor();
Assert.assertSame(fileByMock, actualFile);
}
}

相关内容

最新更新