2010-05-11 42 views
9

我有一个非常简单的文件观察器类,它每2秒检查一次文件是否发生了变化,如果是,则调用onChange方法(void)。 有没有简单的方法来检查在单元测试中onChange方法是否被调用?JUnit:检查一个无效方法是否被调用

代码:

public class PropertyFileWatcher extends TimerTask { 
    private long timeStamp; 
    private File file; 

    public PropertyFileWatcher(File file) { 
     this.file = file; 
     this.timeStamp = file.lastModified(); 
    } 

    public final void run() { 
     long timeStamp = file.lastModified(); 

     if (this.timeStamp != timeStamp) { 
      this.timeStamp = timeStamp; 
      onChange(file); 
     } 
    } 

    protected void onChange(File file) { 
     System.out.println("Property file has changed"); 
    } 
} 

测试:

@Test 
public void testPropertyFileWatcher() throws Exception { 
    File file = new File("testfile"); 
    file.createNewFile(); 
    PropertyFileWatcher propertyFileWatcher = new PropertyFileWatcher(file); 

    Timer timer = new Timer(); 
    timer.schedule(propertyFileWatcher, 2000); 

    FileWriter fw = new FileWriter(file); 
    fw.write("blah"); 
    fw.close(); 

    Thread.sleep(8000); 
    // check if propertyFileWatcher.onChange was called 

    file.delete(); 
} 

回答

16

随着Mockito,您可以验证的方法是否被调用至少一次/永远。

看点4 this page

如:

verify(mockedObject, times(1)).onChange(); // times(1) is the default and can be omitted 
+0

您可以使用任何模拟框架而不是仅仅的Mockito。看看EasyMock或jMock并选择你喜欢的东西。编写单元测试的经验法则是,你只应该模拟你可以控制的对象。换句话说,模拟对象应该使用构造函数参数/设置器或参数传递给被测方法。通过这个逻辑,你不能嘲笑在被测试的类的方法内创建的静态调用,最终的或者私有的,或者“新的”对象。 – Kartik 2010-05-11 23:35:41

+0

任何想法如何在EasyMock中做到这一点?我发现缺乏这方面的文件。当我为PropertyFileWatcher创建一个模拟像这样:PropertyFileWatcher propertyFileWatcher = createMockBuilder(PropertyFileWatcher.class).withConstructor(file).createMock();并将预期的调用记录到onChange并重播:propertyFileWatcher.onChange(file);重放(propertyFileWatcher); onChnage方法立即被调用,并且信息被打印到sysout中,但是我只想验证IF是否调用了该方法 – nkr1pt 2010-05-12 18:26:26

+0

不要使用mockito能够执行AtomicBoolean解决方案。 – 2012-08-10 08:21:27

4

据我了解,你PropertyFileWatcher是为了被继承。那么,为什么不像这样继承它:

class TestPropertyFileWatcher extends PropertyFileWatcher 
{ 
    boolean called = false; 
    protected void onChange(File file) { 
     called = true; 
    } 
} 

... 
TestPropertyFileWatcher watcher = new TestPropertyFileWatcher 
... 
assertTrue(watcher.called); 
7

这是您的测试的一个简单的修改。

@Test 
public void testPropertyFileWatcher() throws Exception { 
    final File file = new File("testfile"); 
    file.createNewFile(); 

    final AtomicBoolean hasCalled = new AtomicBoolean(); 
    PropertyFileWatcher propertyFileWatcher = 
     new PropertyFileWatcher(file) 
     { 
     protected void onChange (final File localFile) 
     { 
      hasCalled.set(true); 
      assertEquals(file, localFile); 
     } 
     } 


    Timer timer = new Timer(); 
    timer.schedule(propertyFileWatcher, 2000); 

    FileWriter fw = new FileWriter(file); 
    fw.write("blah"); 
    fw.close(); 

    Thread.sleep(8000); 
    // check if propertyFileWatcher.onChange was called 

    assertTrue(hasCalled.get()); 
    file.delete(); 
} 
+0

我真的很喜欢这个解决方案,因为它不会增加对模拟框架的依赖;但是嘲笑框架是单元测试的必要条件;这就是为什么我接受嘲笑的建议作为我的问题的接受答案。 – nkr1pt 2010-05-12 17:19:52

+0

@ nkr1pt。肯定会有一个声誉嘲讽的框架。如果您不是仅限于1.4版本的JDK,请查看jMock。 – 2010-05-12 20:50:35