导致 IOException 覆盖 catch 块
Cause IOException to cover catch blocks
我试图覆盖下面代码中的 catch 块,但我做不到。我知道我需要在将 reading/writing 放入文件时引发 IOException,但我做不到。另外,我不能使用 PowerMockito 来覆盖静态方法,因为我正在使用 Junit5。有人可以帮忙吗?
@Override
public String execute(UploadCategoryImageCommandRequest request) {
File tempFile = null;
FileOutputStream fos = null;
String fileName = "";
fileName = UUID.randomUUID().toString() + System.currentTimeMillis() + ".svg";
try {
tempFile = File.createTempFile(fileName, "svg");
fos = new FileOutputStream(tempFile);
fos.write(request.getFile().getBytes());
} catch (IOException e) {
log.error("File Creation Error: {}", e);
upload.setFileStatus(FileStatus.FAILED);
uploadRepository.save(upload);
throw new ApplicationException(ErrorKey.IMAGE_UPLOAD, ErrorCode.FAILED);
}
return string;
}
这是我编写的测试用例之一,但是 returns 这个错误 - org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() 需要一个必须为 'a method call on a mock' 的参数。
例如:
当(mock.getArticles()).thenReturn(文章);
此外,我不确定是否应该在我编写的以下测试用例中模拟文件 class
@Test
public void exception() throws IOException {
Upload upload = Upload.builder().fileStatus(FileStatus.FAILED).imagePath("http://").build();
MockMultipartFile firstFile = new MockMultipartFile("fileName", "fileName.svg", "text/plain", "some xml".getBytes());
UploadCategoryImageCommandRequest uploadCategoryImageCommandRequest = UploadCategoryImageCommandRequest.builder()
.file(firstFile)
.uploadType(UploadType.CATEGORY)
.build();
Mockito.when(file.createTempFile("filename","svg")).thenThrow(IOException.class);
uploadCategoryImageCommand.execute(uploadCategoryImageCommandRequest);
}
静态访问始终是一个问题,不仅在测试上下文中,而且变得最明显。
一种解决方案是将静态访问置于非静态方法中的单独 class 中。这个 class 将“太简单而不会失败”,因此没有代码覆盖率是合理的。将此助手 class 的一个实例作为构造函数参数注入到您的 待测代码 中。然后你可以简单地用 mock 替换它,在那个特定的测试中抛出所需的异常。
Can you explain this with an example? - Meg
新的 class(不需要单元测试 -> 覆盖率 0%)
class TempFileCreator{
File createTempFile(String baseName, String extension){
return File.createTempFile(fileName, extension);
}
}
被测代码的更改 (CUT):
class YourClass{
private final TempFileCreator tempFileCreator;
YourClass(TempFileCreator tempFileCreator
/* more constructor parameters? */
/* update the Builder, may hold an instance of TempFileCreator as a constant */
){
this.tempFileCreator = tempFileCreator;
}
@Override
public Single<String> execute(UploadCategoryImageCommandRequest request) {
// lots of your code
try {
// more of your code
File tempfile = tempFileCreator.createTempFile(fileName, "svg");
// tempfile.deleteOnExit(); would prevent the extra section in finally block...
// more of your code
} catch (IOException e) {
// the code to verify (coverage does not have a value as such...)
}
}
}
你的测试:
@Mock
TempFileCreator tempFileCreator; // should be injected to your CUT like the other mocks...
@Test
public void exception() throws IOException {
Mockito.doThrow(new IOException("this is a test")).when(tempFileCreator).createTempFile(anyString(),anyString());
// prefer this form since it does not execute the mocked method while the when().then*() form does...
// the rest of yout test code
}
File.createTempFile
在默认临时目录中创建一个文件,您可以通过设置 java.io.tmpdir
系统 属性 来覆盖它。如果你将它设置到某个不存在的目录,临时文件创建将失败,你会得到一个 IOException
。只要确保在完成后恢复它,就不会搞乱其余的测试。 JUnit Pioneer 的 SetSystemProperty
提供了一种优雅的方式来做到这一点:
@Test
@SetSystemProperty(key = "java.io.tmpdir", value = "/no/such/dir")
public void exception() throws IOException {
// Call your code
}
我试图覆盖下面代码中的 catch 块,但我做不到。我知道我需要在将 reading/writing 放入文件时引发 IOException,但我做不到。另外,我不能使用 PowerMockito 来覆盖静态方法,因为我正在使用 Junit5。有人可以帮忙吗?
@Override
public String execute(UploadCategoryImageCommandRequest request) {
File tempFile = null;
FileOutputStream fos = null;
String fileName = "";
fileName = UUID.randomUUID().toString() + System.currentTimeMillis() + ".svg";
try {
tempFile = File.createTempFile(fileName, "svg");
fos = new FileOutputStream(tempFile);
fos.write(request.getFile().getBytes());
} catch (IOException e) {
log.error("File Creation Error: {}", e);
upload.setFileStatus(FileStatus.FAILED);
uploadRepository.save(upload);
throw new ApplicationException(ErrorKey.IMAGE_UPLOAD, ErrorCode.FAILED);
}
return string;
}
这是我编写的测试用例之一,但是 returns 这个错误 - org.mockito.exceptions.misusing.MissingMethodInvocationException: when() 需要一个必须为 'a method call on a mock' 的参数。 例如: 当(mock.getArticles()).thenReturn(文章);
此外,我不确定是否应该在我编写的以下测试用例中模拟文件 class
@Test
public void exception() throws IOException {
Upload upload = Upload.builder().fileStatus(FileStatus.FAILED).imagePath("http://").build();
MockMultipartFile firstFile = new MockMultipartFile("fileName", "fileName.svg", "text/plain", "some xml".getBytes());
UploadCategoryImageCommandRequest uploadCategoryImageCommandRequest = UploadCategoryImageCommandRequest.builder()
.file(firstFile)
.uploadType(UploadType.CATEGORY)
.build();
Mockito.when(file.createTempFile("filename","svg")).thenThrow(IOException.class);
uploadCategoryImageCommand.execute(uploadCategoryImageCommandRequest);
}
静态访问始终是一个问题,不仅在测试上下文中,而且变得最明显。
一种解决方案是将静态访问置于非静态方法中的单独 class 中。这个 class 将“太简单而不会失败”,因此没有代码覆盖率是合理的。将此助手 class 的一个实例作为构造函数参数注入到您的 待测代码 中。然后你可以简单地用 mock 替换它,在那个特定的测试中抛出所需的异常。
Can you explain this with an example? - Meg
新的 class(不需要单元测试 -> 覆盖率 0%)
class TempFileCreator{
File createTempFile(String baseName, String extension){
return File.createTempFile(fileName, extension);
}
}
被测代码的更改 (CUT):
class YourClass{
private final TempFileCreator tempFileCreator;
YourClass(TempFileCreator tempFileCreator
/* more constructor parameters? */
/* update the Builder, may hold an instance of TempFileCreator as a constant */
){
this.tempFileCreator = tempFileCreator;
}
@Override
public Single<String> execute(UploadCategoryImageCommandRequest request) {
// lots of your code
try {
// more of your code
File tempfile = tempFileCreator.createTempFile(fileName, "svg");
// tempfile.deleteOnExit(); would prevent the extra section in finally block...
// more of your code
} catch (IOException e) {
// the code to verify (coverage does not have a value as such...)
}
}
}
你的测试:
@Mock
TempFileCreator tempFileCreator; // should be injected to your CUT like the other mocks...
@Test
public void exception() throws IOException {
Mockito.doThrow(new IOException("this is a test")).when(tempFileCreator).createTempFile(anyString(),anyString());
// prefer this form since it does not execute the mocked method while the when().then*() form does...
// the rest of yout test code
}
File.createTempFile
在默认临时目录中创建一个文件,您可以通过设置 java.io.tmpdir
系统 属性 来覆盖它。如果你将它设置到某个不存在的目录,临时文件创建将失败,你会得到一个 IOException
。只要确保在完成后恢复它,就不会搞乱其余的测试。 JUnit Pioneer 的 SetSystemProperty
提供了一种优雅的方式来做到这一点:
@Test
@SetSystemProperty(key = "java.io.tmpdir", value = "/no/such/dir")
public void exception() throws IOException {
// Call your code
}