在没有模拟迭代器的情况下模拟 DirectoryStream<Path> 可能吗?
Mocking DirectoryStream<Path> without mocking iterator possible?
我有以下代码:
Map<String, String> fileContentsByName = new HashMap<String, String>();
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(directory))
{
for (Path path : directoryStream)
{
if (Files.isRegularFile(path))
{
fileContentsByName.put(path.getFileName().toString(), new String(Files.readAllBytes(path)));
}
}
}
catch (IOException e)
{
}
我正在尝试测试这个方法。我正在使用 Powermock
来获取模拟的 DirectoryStream<Path>
。然而,当测试在代码中遇到 for-each 时,它就炸毁了一个 NPE。如何在 DirectoryStream 中指定路径?
我考虑过更改源代码以使用迭代器并模拟 DirectoryStream 的迭代器以提供所需的路径,但我想知道是否有更好的选择?
假设您在上面提供的代码片段在 class 中定义如下:
public class DirectoryStreamReader {
public Map<String, String> read(Path directory) {
Map<String, String> fileContentsByName = new HashMap<String, String>();
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(directory)) {
for (Path path : directoryStream) {
if (Files.isRegularFile(path)) {
fileContentsByName.put(path.getFileName().toString(), new String(Files.readAllBytes(path)));
}
}
} catch (IOException e) {
}
return fileContentsByName;
}
}
那么下面的测试就会通过:
@RunWith(PowerMockRunner.class)
@PrepareForTest({DirectoryStreamReader.class})
public class DirectoryStreamTest {
@Rule
public TemporaryFolder folder= new TemporaryFolder();
@Test
public void canReadFilesUsingDirectoryStream() throws IOException {
PowerMockito.mockStatic(Files.class);
Path directory = Mockito.mock(Path.class);
DirectoryStream<Path> expected = Mockito.mock(DirectoryStream.class);
Mockito.when(Files.newDirectoryStream(Mockito.any(Path.class))).thenReturn(expected);
File fileOne = folder.newFile();
File fileTwo = folder.newFile();
Iterator<Path> directoryIterator = Lists.newArrayList(Paths.get(fileOne.toURI()),
Paths.get(fileTwo.toURI())).iterator();
Mockito.when(expected.iterator()).thenReturn(directoryIterator);
Mockito.when(Files.isRegularFile(Mockito.any(Path.class))).thenReturn(true);
Mockito.when(Files.readAllBytes(Mockito.any(Path.class))).thenReturn("fileOneContents".getBytes()).thenReturn("fileTwoContents".getBytes());
Map<String, String> fileContentsByName = new DirectoryStreamReader().read(directory);
Assert.assertEquals(2, fileContentsByName.size());
Assert.assertTrue(fileContentsByName.containsKey(fileOne.getName()));
Assert.assertEquals("fileOneContents", fileContentsByName.get(fileOne.getName()));
Assert.assertTrue(fileContentsByName.containsKey(fileTwo.getName()));
Assert.assertEquals("fileTwoContents", fileContentsByName.get(fileTwo.getName()));
}
}
这里的重点是:
- 使用 JUnit 的
TemporaryFolder
规则创建和丢弃一些供测试使用的文件
- 使用 PowerMockito 模拟与
java.nio.file.Files
的所有交互,这是最终的 class 并且被模拟的方法是静态的,因此需要 PowerMockito
- 在 mocking a system class 时遵循 PowerMockito 建议,特别是:
- 在测试用例的 class 级别使用
@RunWith(PowerMockRunner.class)
注释。
- 在测试用例的 class 级别使用
@PrepareForTest({ClassThatCallsTheSystemClass.class})
注释。
- 使用
mockStatic(SystemClass.class)
模拟系统class
- 此测试已通过 Junit 4.12、Mockito 2.7.19 和 PowerMock 1.7.0 验证
我有以下代码:
Map<String, String> fileContentsByName = new HashMap<String, String>();
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(directory))
{
for (Path path : directoryStream)
{
if (Files.isRegularFile(path))
{
fileContentsByName.put(path.getFileName().toString(), new String(Files.readAllBytes(path)));
}
}
}
catch (IOException e)
{
}
我正在尝试测试这个方法。我正在使用 Powermock
来获取模拟的 DirectoryStream<Path>
。然而,当测试在代码中遇到 for-each 时,它就炸毁了一个 NPE。如何在 DirectoryStream 中指定路径?
我考虑过更改源代码以使用迭代器并模拟 DirectoryStream 的迭代器以提供所需的路径,但我想知道是否有更好的选择?
假设您在上面提供的代码片段在 class 中定义如下:
public class DirectoryStreamReader {
public Map<String, String> read(Path directory) {
Map<String, String> fileContentsByName = new HashMap<String, String>();
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(directory)) {
for (Path path : directoryStream) {
if (Files.isRegularFile(path)) {
fileContentsByName.put(path.getFileName().toString(), new String(Files.readAllBytes(path)));
}
}
} catch (IOException e) {
}
return fileContentsByName;
}
}
那么下面的测试就会通过:
@RunWith(PowerMockRunner.class)
@PrepareForTest({DirectoryStreamReader.class})
public class DirectoryStreamTest {
@Rule
public TemporaryFolder folder= new TemporaryFolder();
@Test
public void canReadFilesUsingDirectoryStream() throws IOException {
PowerMockito.mockStatic(Files.class);
Path directory = Mockito.mock(Path.class);
DirectoryStream<Path> expected = Mockito.mock(DirectoryStream.class);
Mockito.when(Files.newDirectoryStream(Mockito.any(Path.class))).thenReturn(expected);
File fileOne = folder.newFile();
File fileTwo = folder.newFile();
Iterator<Path> directoryIterator = Lists.newArrayList(Paths.get(fileOne.toURI()),
Paths.get(fileTwo.toURI())).iterator();
Mockito.when(expected.iterator()).thenReturn(directoryIterator);
Mockito.when(Files.isRegularFile(Mockito.any(Path.class))).thenReturn(true);
Mockito.when(Files.readAllBytes(Mockito.any(Path.class))).thenReturn("fileOneContents".getBytes()).thenReturn("fileTwoContents".getBytes());
Map<String, String> fileContentsByName = new DirectoryStreamReader().read(directory);
Assert.assertEquals(2, fileContentsByName.size());
Assert.assertTrue(fileContentsByName.containsKey(fileOne.getName()));
Assert.assertEquals("fileOneContents", fileContentsByName.get(fileOne.getName()));
Assert.assertTrue(fileContentsByName.containsKey(fileTwo.getName()));
Assert.assertEquals("fileTwoContents", fileContentsByName.get(fileTwo.getName()));
}
}
这里的重点是:
- 使用 JUnit 的
TemporaryFolder
规则创建和丢弃一些供测试使用的文件 - 使用 PowerMockito 模拟与
java.nio.file.Files
的所有交互,这是最终的 class 并且被模拟的方法是静态的,因此需要 PowerMockito - 在 mocking a system class 时遵循 PowerMockito 建议,特别是:
- 在测试用例的 class 级别使用
@RunWith(PowerMockRunner.class)
注释。 - 在测试用例的 class 级别使用
@PrepareForTest({ClassThatCallsTheSystemClass.class})
注释。 - 使用
mockStatic(SystemClass.class)
模拟系统class
- 在测试用例的 class 级别使用
- 此测试已通过 Junit 4.12、Mockito 2.7.19 和 PowerMock 1.7.0 验证