PowerkMock-ing BufferedReader 间歇运行
PowerkMock-ing BufferedReader runs interminately
我想做的是模拟新创建的 BufferedReader
实例。这是应该测试的代码:
A.java
...
@Override
public String read(String fileName) throws IOException {
...
try {
fileReader = new FileReader(fileName);
bufferedReader = new BufferedReader(fileReader);
String tmp;
StringBuilder builder = new StringBuilder();
while ((tmp = bufferedReader.readLine()) != null) {
builder.append(tmp);
}
return builder.toString();
} catch (IOException e) {
...
} finally {
...
}
}
...
我必须做的是 PowerMock FileReader
创建和 BufferedReader
创建。
ATest.java
@RunWith(PowerMockRunner.class)
@PrepareForTest(A.class)
public class ATest {
@Mock
private FileReader fileReader;
@Mock
private BufferedReader bufferedReader;
...
@Test
public void test() throws Exception {
PowerMockito.whenNew(FileReader.class).withArguments(FILE_NAME).thenReturn(fileReader);
PowerMockito.whenNew(BufferedReader.class).withAnyArguments().thenReturn(bufferedReader);
PowerMockito.doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) throws Throwable {
return "test";
}
}).when(bufferedReader).readLine();
assertArrayEquals(reader.read(FILE_NAME), new String[]{"test"});
}
}
但是测试永远不会终止。我什至不能调试它。
一旦 PowerMockito.doAnswer()
被删除,代码就会被执行(并且可用于调试)。我也尝试过使用 Mockito.mock()
而不是 PowerMockito.doAnswer()
,但没有用。
什么可能导致测试终止执行?
问题是,我还必须在第一个 bufferedReader.readLine()
之后模拟值,否则它总是 return 模拟值,因此不会终止。
Mockito.when(bufferedReader.readLine()).thenReturn("first line").thenReturn(null);
注意
虽然这是问题的实际答案,但您应该强烈考虑在另一个答案(我最终选择了)中选择设计 。
只是换个角度:可以说代码中的 真正的 问题是对 new()
for FileReader / Buffered[ 的两次调用=43=]。
如果您将 Reader 传递给此方法会怎么样?而不是表示文件名的字符串?
如果将 "ReaderFactory" 传递给包含此方法 read(String)
的底层 class 会怎样? (您将使用 依赖注入 将该工厂放入您的 class)
然后:您将查看 改进的 设计 - 您 不需要 需要使用 PowerMock。您可以退后一步,使用 Mockito 或 EasyMock;因为不再需要模拟调用 new
.
所以,我的回答是:您创建了 hard-to-test 代码。现在您尝试使用大(丑陋)的 PowerMock 锤子修复设计问题。是的,那会起作用。但它只是第二好的选择。
更合理的选择是学习如何编写可测试的代码(例如开始here);好吧,编写可测试的代码。并停止使用 PowerMock(我几个月前就这样做了;在经历了很多 PowerMock-induced 痛苦之后;我 从来没有 后悔这个决定)。
我想做的是模拟新创建的 BufferedReader
实例。这是应该测试的代码:
A.java
...
@Override
public String read(String fileName) throws IOException {
...
try {
fileReader = new FileReader(fileName);
bufferedReader = new BufferedReader(fileReader);
String tmp;
StringBuilder builder = new StringBuilder();
while ((tmp = bufferedReader.readLine()) != null) {
builder.append(tmp);
}
return builder.toString();
} catch (IOException e) {
...
} finally {
...
}
}
...
我必须做的是 PowerMock FileReader
创建和 BufferedReader
创建。
ATest.java
@RunWith(PowerMockRunner.class)
@PrepareForTest(A.class)
public class ATest {
@Mock
private FileReader fileReader;
@Mock
private BufferedReader bufferedReader;
...
@Test
public void test() throws Exception {
PowerMockito.whenNew(FileReader.class).withArguments(FILE_NAME).thenReturn(fileReader);
PowerMockito.whenNew(BufferedReader.class).withAnyArguments().thenReturn(bufferedReader);
PowerMockito.doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) throws Throwable {
return "test";
}
}).when(bufferedReader).readLine();
assertArrayEquals(reader.read(FILE_NAME), new String[]{"test"});
}
}
但是测试永远不会终止。我什至不能调试它。
一旦 PowerMockito.doAnswer()
被删除,代码就会被执行(并且可用于调试)。我也尝试过使用 Mockito.mock()
而不是 PowerMockito.doAnswer()
,但没有用。
什么可能导致测试终止执行?
问题是,我还必须在第一个 bufferedReader.readLine()
之后模拟值,否则它总是 return 模拟值,因此不会终止。
Mockito.when(bufferedReader.readLine()).thenReturn("first line").thenReturn(null);
注意
虽然这是问题的实际答案,但您应该强烈考虑在另一个答案(我最终选择了)中选择设计
只是换个角度:可以说代码中的 真正的 问题是对 new()
for FileReader / Buffered[ 的两次调用=43=]。
如果您将 Reader 传递给此方法会怎么样?而不是表示文件名的字符串?
如果将 "ReaderFactory" 传递给包含此方法 read(String)
的底层 class 会怎样? (您将使用 依赖注入 将该工厂放入您的 class)
然后:您将查看 改进的 设计 - 您 不需要 需要使用 PowerMock。您可以退后一步,使用 Mockito 或 EasyMock;因为不再需要模拟调用 new
.
所以,我的回答是:您创建了 hard-to-test 代码。现在您尝试使用大(丑陋)的 PowerMock 锤子修复设计问题。是的,那会起作用。但它只是第二好的选择。
更合理的选择是学习如何编写可测试的代码(例如开始here);好吧,编写可测试的代码。并停止使用 PowerMock(我几个月前就这样做了;在经历了很多 PowerMock-induced 痛苦之后;我 从来没有 后悔这个决定)。