我一直在从事一个包含许多 UI 组件的项目。由于所有组件都基于 MVC 模式,因此它们被构造为一个组件——公共接口和工厂,封装受保护的模型/视图/控制器。
“手动”测试它们 - 使用模拟技术太困难且耗时。
所以我加入了 Fest 框架 - http://fest.easytesting.org/。这很简单,很好并且可以完成工作。
当我尝试同时使用 JMockit - http://code.google.com/p/jmockit/和 Fest 时出现问题。我注意到 Fest 使用了一些可能与 JMockit 冲突的库——反射和断言。
当我运行测试时,JMockit 不会模拟所需的类。我以前使用过 JMockit,所以我很确定这是库之间的某种冲突。模拟类上没有生成 $Proxy$,当然,该类行为不端。
需要模拟,因为我必须测试完整的组件交互!
版本:
JMockit:0.999.8
巨星:
Fest-swing 1.2.1 Fest-assert 1.4 Fest-util 1.1.6 Fest-reflect 1.2
我无意通过查看两个库来寻找冲突,所以任何帮助都会很感激。
谢谢。
更新:
测试/示例代码在这里:
public interface SimpleControllable {
void init();
JPanel getPanel();
}
public class SimpleController implements SimpleControllable {
private final SimpleForm simpleForm;
private final SimpleModel simpleModel;
public SimpleController(
final SimpleForm simpleForm,
final SimpleModel simpleModel
) {
this.simpleForm = simpleForm;
this.simpleModel = simpleModel;
}
@Override
public void init() {
simpleForm.init();
//This works!
/*simpleForm.getTestButton().addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
simpleForm.getTestButton().setText(simpleModel.getSimpleValue());
}
});*/
//This doesn't!
simpleForm.getTestButton().setText(simpleModel.getSimpleValue());
}
@Override
public JPanel getPanel() {
return simpleForm.getTestPanel();
}
}
public class SimpleModel {
private final SimpleServable simpleServable;
public SimpleModel(final SimpleServable simpleServable) {
this.simpleServable = simpleServable;
}
public String getSimpleValue() {
return simpleServable.getValue();
}
}
public interface SimpleServable {
String getValue();
}
public class SimpleService implements SimpleServable {
private String value;
@Override
public String getValue() {
return value;
}
}
public class SimpleForm {
private JButton testButton;
private JPanel testPanel;
public void init() {
testPanel.setName("testPanel");
testButton.setName("testButton");
}
public JButton getTestButton() {
return testButton;
}
public JPanel getTestPanel() {
return testPanel;
}
}
public class SimpleTest extends FestSwingJUnitTestCase {
@Mocked
private SimpleService simpleServable;
private FrameFixture window;
@Override
protected void onSetUp() {
FailOnThreadViolationRepaintManager.install();
JFrame frameUi = GuiActionRunner.execute(new GuiQuery<JFrame>() {
protected JFrame executeInEDT() {
SimpleControllable simpleControllable = getSimpleControllable();
JFrame frame = new JFrame("TEST");
frame.add(simpleControllable.getPanel());
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
return frame;
}
});
robot().settings().delayBetweenEvents(1000);
// IMPORTANT: note the call to 'robot()'
// we must use the Robot from FestSwingTestngTestCase
window = new FrameFixture(robot(), frameUi);
window.show(); // shows the frameU
}
//Should use factory, but not neccesary for test purposes...
private SimpleControllable getSimpleControllable() {
SimpleForm simpleForm = new SimpleForm();
//SimpleServable simpleServable = new SimpleService();
SimpleModel simpleModel = new SimpleModel(simpleServable);
SimpleControllable simpleControllable = new SimpleController(
simpleForm,
simpleModel
);
//Initialize the component, therein lies the problem...
simpleControllable.init();
return simpleControllable;
}
@Test
public void test() throws Exception {
//Before
new Expectations() {
{
simpleServable.getValue();
result = "TEST";
}
};
//When
//This works!
// window.panel("testPanel").button("testButton").click().requireText("TEST");
//This doesn't!
window.panel("testPanel").button("testButton").requireText("TEST");
//Then
}
}
看来我太早归咎于框架了。但我仍然不明白为什么它不起作用的细节。类Service被嘲笑,它应该仍然可以使用,即使在延迟了期望之后。我了解时间问题(组件的初始化),但不知道如何“解决”这个问题。
谢谢。
更新2:
谢谢,罗杰里奥。您可以使用 FEST 测试组件,但它并没有真正利用 JMockit,而且有些类有很多方法(是的,我知道 - SRP,但让我们尝试继续走这条路)并且会受益匪浅来自模拟框架,例如 JMockit。我在这里发布问题之前使用了它,因此您可以自己使用它,并了解这不是我想要的方式:
public class SimpleTest extends FestSwingJUnitTestCase {
//This works, and I used this mechanism before, but this is without the help of JMockit.
//If you have a lot of methods you want to mock this test turns into chaos.
public static class MockSimpleServable implements SimpleServable{
@Override
public String getValue() {
return "TEST";
}
}
// @Mocked
// private SimpleServable simpleServable;
private FrameFixture window;
@Override
protected void onSetUp() {
FailOnThreadViolationRepaintManager.install();
JFrame frameUi = GuiActionRunner.execute(new GuiQuery<JFrame>() {
protected JFrame executeInEDT() {
SimpleControllable simpleControllable = getSimpleControllable();
JFrame frame = new JFrame("TEST");
frame.add(simpleControllable.getPanel());
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
return frame;
}
});
robot().settings().delayBetweenEvents(1000);
// IMPORTANT: note the call to 'robot()'
// we must use the Robot from FestSwingTestngTestCase
window = new FrameFixture(robot(), frameUi);
window.show(); // shows the frameU
}
//Should use factory, but not neccesary for test purposes...
private SimpleControllable getSimpleControllable() {
SimpleForm simpleForm = new SimpleForm();
//SimpleServable simpleServable = new SimpleService();
SimpleServable simpleServable = new MockSimpleServable();
SimpleModel simpleModel = new SimpleModel(simpleServable);
SimpleControllable simpleControllable = new SimpleController(
simpleForm,
simpleModel
);
//Initialize the component, therein lies the problem...
simpleControllable.init();
return simpleControllable;
}
@Test
public void test() throws Exception {
//This works!
// window.panel("testPanel").button("testButton").click().requireText("TEST");
//This doesn't!
window.panel("testPanel").button("testButton").requireText("TEST");
}
}
问题仍然存在 - 有没有人知道我可以用 JMockit 测试它,不要忘记 EDT 违规。