2017-02-11 130 views
1

我想要做的是模拟BufferedReader新创建的实例。这里是一个应该被测试代码:PowerkMocking 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创建FileReaderBufferedReader创作。

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(),它没有帮助。

什么可能会导致测试的中断执行?

回答

1

问题是,我还必须在第一个bufferedReader.readLine()后模拟值,因为否则它总是会返回模拟值,因此不会终止。

Mockito.when(bufferedReader.readLine()).thenReturn("first line").thenReturn(null); 

注意

虽然这是实际的问题的答案,但你应当认真考虑在另一个答案选择设计GhostCat has suggested(我最终没有)。

3

只是一个不同的观点:人们可以说你的代码中的真实问题是对FileReader/BufferedReader的new()的两次调用。

如果您将Reader传递给此方法会怎样?而不是一个字符串表示文件名?

如果您将“ReaderFactory”传递给包含此方法的基础类,该怎么办?read(String)? (在这里您将使用依赖注入到工厂进入类)

然后:你会在看一个改进设计 - 你会不会需要使用PowerMock。你可以退后一步,并与Mockito或EasyMock一起去;因为将不再需要模拟new的呼叫。

所以,我的答案是:你创建了难以测试的代码。现在,您尝试使用大型(丑陋)PowerMock锤子修复设计问题。是的,那会起作用。但它只是第二好的选择。

更合理的选择是学习如何编写可测试代码(例如,开始here);并编写可测试的代码。并停止使用PowerMock(我已经完成了那么多个月;经过了很多PowerMock引起的痛苦;并且我有永远不会后悔这个决定)。

+0

谢谢,非常有道理。 – azizbekian

+1

非常欢迎。我总是很高兴,当人们不回复这样的答案时,“但它不是我的代码,我必须测试;所以PowerMock是我的唯一选择”;-) – GhostCat

+1

而且正如旁注:FileUtilities.readAllLines ) - 接受一个字符串,并返回该文件中所有行的列表(您可以轻松地连接以获取单个字符串)。因此,可能不是重新实现第10次“完全读入字符串”,您也可以使用其中一个现有的实现。我确定apache commons,番石榴,他们都有这个方法! – GhostCat