Junit 和 EasyMock 意外失败

Junit and EasyMock unexpected failure

各位程序员大家好。在我决定在这里 post 之前,我在互联网上(包括在 Whosebug 上)浏览了数十种 "suggested" 补救措施。但无济于事。

所以。我在 JSF 中开始了一个小项目。在使用 JSFUnit 和 Apache Cactus 测试 UIComponents 和托管 Bean 之间的关系失败后(这是另一个悲伤的故事),我希望至少能够测试域模型单元。唉。

我有这个 POJO:

public class AppointmentFormBean implements Serializable, Observed{
private Date selectedDate;
private ArrayList<VGObserver> observers;
/**
 * Creates a new instance of AppointmentFormBean
 */
public AppointmentFormBean() {
    observers = new ArrayList<>();
}

public Date getSelectedDate() {
    return selectedDate;
}

public void setSelectedDate(Date selectedDate) {
    this.selectedDate = selectedDate;
    notifyVGObservers();
}

@Override
public void registerVGObserver(VGObserver o) {
    this.observers.add(o);
}

@Override
public void removeVGObserver(VGObserver o) {
    int i = observers.indexOf(o);
    if(i>=0)
        observers.remove(o);
}

@Override
public void notifyVGObservers() {
    observers.stream().map((observer1) -> (VGObserver) observer1).forEach((observer) -> {
        observer.update(selectedDate);
    });
}

}

(我故意省略了 JSF 注释 - 它们与我的测试无关 运行)

这个POJO实现的Observed接口是这样的:

public interface Observed {
public void registerVGObserver(VGObserver o);
public void removeVGObserver(VGObserver o);
public void notifyVGObservers();

}

Yip,从读过它的 Head First Design Patterns 复制而来:-)

VGObserver,上面提到的 - 是另一个接口,它将 "listen" 到 classes 实现中的变化 Observed:

public interface VGObserver {
public void update(Date selectedDate);

}

我对这个设计有很大的计划,因为最终 VGObserver(具体 class 实现它)将尝试检索 REST 资源 - 过去日期的天气。但是我们跑题了。

最后,我构建了测试 class 以检查每次 setSelectedBean(...) 被调用时,VGObserver 的 update(. ..) 被触发。我使用 Easy Mock 来模拟 VGObserver 接口:

public class AppointmentBeanObservableTest {

private AppointmentFormBean form;
private VGObserver mockObserver;
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

@Before
public void setUp() {
    form = new AppointmentFormBean();
    mockObserver = createMock("observer", VGObserver.class);
    form.registerVGObserver(mockObserver);
}

@After
public void tearDown() {
    verify(mockObserver);
}

@Test
public void testIocForVGObserved() throws ParseException {        
    Date aDate = sdf.parse("2015-09-15");
    form.setSelectedDate(aDate);
    mockObserver.update(aDate);
    EasyMock.expectLastCall().anyTimes();
    replay(mockObserver);
}

}

不幸的是,这个测试完全失败了,我找不到任何可以修复的东西。以下是 github:

上的输出和项目 link
Time elapsed: 0.091 sec  <<< FAILURE!
java.lang.AssertionError:   Expectation failure on verify:
observer.update(Tue Sep 15 00:00:00 EDT 2015): expected: at least 1, actual: 0
at org.easymock.internal.MocksControl.verify(MocksControl.java:241)
at org.easymock.EasyMock.verify(EasyMock.java:2100)
at com.vgorcinschi.rimmanew.model.AppointmentBeanObservableTest.tearDown(AppointmentBeanObservableTest.java:40)

Results :
Failed tests: 
 AppointmentBeanObservableTest.tearDown:40 
 Expectation failure on verify:
observer.update(Tue Sep 15 00:00:00 EDT 2015): expected: at least 1, actual: 0
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0

https://github.com/vasigorc/rimmaproject

如有任何提示,我们将不胜感激。

你搞反了。

在调用实际的被测系统 (SUT) 之前,您必须告诉 mock 期望什么。然后在设置期望后,您可以在 replay 模式下进行模拟。然后最后你调用你的系统进行测试。

您首先调用了被测系统,然后设置了模拟。

将其更改为:

 @Test
 public void testIocForVGObserved() throws ParseException {        
     Date aDate = sdf.parse("2015-09-15");

     mockObserver.update(aDate);
     EasyMock.expectLastCall().anyTimes();
     replay(mockObserver);

     //call SUT now
     form.setSelectedDate(aDate);
}

应该可以。

您也可以删除 expectLastCall().anyTimes() 行。由于有关模拟如何在记录模式下调用的实现细节,您的向后设置可能会为调用设置 2 个期望值。一旦你确定了设置的顺序并重播它应该只被调用一次。