我将尝试提供一些指示。
1)在这里,我不会模拟整个逻辑来检查文件的存在,因为它是被测方法行为的一部分。
您要模拟的是您实际尝试检索文件的部分,即在您调用getFilefromLocation()
.
2)在重试之间使用短暂的延迟是一个想法,但这足以使您的测试稳健吗?
不是真的,因为您还必须断言Thread.sleep()
已调用并具有预期值。在单元测试中不检查意味着任何人都可以Thread.sleep()
在getFile()
方法中删除并且测试仍然会通过。你真的不想要那个。
请注意,您不能轻易地模拟它:它是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);
}
}