我有一个带有重试逻辑的方法。重试逻辑是使用自定义注释实现的。我想要一个单元测试来验证在抛出某个异常时是否再次调用该方法。
public class FileTest {
String first;
String second;
Instant third;
int fourth;
@Tested
StoreFiles storeFiles;
@Injectable
FileSystemFactory fileSystemFactory;
@Mocked
OracleConnection conn;
@Before public void initMocks() {
MockitoAnnotations.initMocks(StoreFiles.class);
}
@BeforeClass()
public void init() {
first= "test";
second= "testRoot";
third= Instant.now();
fourth= 1;
}
@Test
public void testRetry(@Mocked FileSystemFactory fileSystemFactory,
@Mocked StructDescriptor dbDataRecDesc,
@Mocked ArrayDescriptor dbDataTabDesc) throws CustomException {
StoreFiles files = mock(StoreFiles.class);
files.storeFiles(conn, first, second, third, fourth);
Mockito.verify(files, times(2)).storeFiles(conn, first, second, third, fourth);
}
}
当前使用jmockit、testng 和mockito。我只需要确保在抛出 CustomException
时再次调用 storeFile
方法。如果我使用 storeFiles
对象而不是 files
对象,则会抛出我想要的异常。如果我像此处编写的那样运行测试,则会收到一条错误,指出 storeFiles 方法仅被调用一次,指的是我在测试方法中显式调用它的位置。两者都会导致我正在测试的方法无法重试。
最佳答案
这很难测试,因为 StoreFiles::storeFile
方法正在做两件事:存储文件和执行重试逻辑。您可以更改您的设计以使其更具可测试性。这是我的建议:
首先,从 StoreFiles::storeFile 中删除重试逻辑,并将其提取到具有该职责的另一个类:
public class Retry {
public void exec(Runnable r) {
try {
r.run();
} catch (CustomException e) {
r.run();
}
}
}
现在,您可以像这样编写重试逻辑测试:
public class RetryTest {
//fields and init method
@Test
public void test() {
Retry retry = new Retry();
Mockito
.doThrow(new CustomException()) //first StoreFiles::storeFile call, throws exeption
.doNothing() //second StoreFiles::storeFile call, does nothing
.when(storeFiles).storeFile(conn, first, second, third, fourth);
retry.exec(() -> storeFiles.storeFile(conn, first, second, third, fourth));
//verify StoreFiles::storeFile is called twice
Mockito.verify(storeFiles, Mockito.times(2)).storeFile(conn, first, second, third, fourth);
}
}
(我假设 CustomException 是一个非检查异常)
另一个解决方案是实现装饰器模式并构建一个RetryStoreFiles
:
public class RetryStoreFiles implements StoreFiles {
private final StoreFiles decorated;
public RetryStoreFiles(StoreFiles decorated) {
this.decorated = decorated;
}
@Override
public void storeFile(conn: Conn, first: First, second: Second, third: Third, fourth: Fourth) {
try {
decorated.storeFile(conn, first, second, third, fourth);
} catch (CustomException e) {
decorated.storeFile(conn, first, second, third, fourth);
}
}
}
我更喜欢第二种解决方案。我认为它比第一个更语义化和面向对象。
关于java - 对具有重试逻辑的方法进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57430196/