我正在尝试熟悉TDD和Presenter First模式。现在,我一直在为我的Presenter.class编写测试用例。我的目标是涵盖整个Presenter.class,包括Action事件,但我不知道如何使用Mockito做到这一点。
Presenter.class:
public class Presenter {
IModel model;
IView view;
public Presenter(final IModel model, final IView view) {
this.model = model;
this.view = view;
this.model.addModelChangesListener(new AbstractAction() {
public void actionPerformed(ActionEvent arg0) {
view.setText(model.getText());
}
});
}}IView.class:
public interface IView {
public void setText(String text);
}IModel.class:
public interface IModel {
public void setText();
public String getText();
public void whenModelChanges();
public void addModelChangesListener(AbstractAction action);
}PresenterTest.class:
@RunWith(MockitoJUnitRunner.class)
public class PresenterTest {
@Mock
IView view;
@Mock
IModel model;
@Before
public void setup() {
new Presenter(model, view);
}
@Test
public void test1() {
}
}提前感谢!
发布于 2012-07-16 00:39:21
起初..。谢谢你们!
过了一段时间,我找到了这个解决方案,并坚持使用它,因为我既不想在presenter类中实现任何接口,也不想在测试中创建存根类。
IView
public interface IView {
public void setText(String text);
}IModel
public interface IModel {
public String getText();
public void addModelChangeListener(Action a);
}演示者
public class Presenter {
private IModel model;
private IView view;
public Presenter(final IModel model, final IView view) {
this.model = model;
this.view = view;
model.addModelChangeListener(new AbstractAction() {
public void actionPerformed(ActionEvent e) {
view.setText(model.getText());
}
});
}
}PresenterTest
@RunWith(MockitoJUnitRunner.class)
public class PresenterTest {
@Mock
IView view;
@Mock
IModel model;
@Test
public void when_model_changes_presenter_should_update_view() {
ArgumentCaptor<Action> event = ArgumentCaptor.forClass(Action.class);
when(model.getText()).thenReturn("test-string");
new Presenter(model, view);
verify(model).addModelChangeListener(event.capture());
event.getValue().actionPerformed(null);
verify(view).setText("test-string");
}
}发布于 2012-07-02 10:07:20
在这种情况下,模型和presenter之间的连接足够松散(通过操作侦听器进行通信),因此您最好不要对模型使用mock。
您可以使用真实的模型(如果真实的模型足够简单,我更愿意这样做),或者像我在下面的代码片段中所做的那样,在您的测试代码中创建一个存根。
@RunWith(MockitoJUnitRunner.class)
public class PresenterTest {
@Mock
IView view;
IModel model;
@Before
public void setup() {
model = new StubModel();
new Presenter(model, view);
}
@Test
public void presenterUpdatesViewWhenModelChanges() {
model.setText("Test Text");
verify(view).setText("Test Text");
}
private class StubModel implements IModel {
private String text;
private List<ActionListener> actionListeners;
StubModel() {
actionListeners = new ArrayList<ActionListener>();
}
@Override
public void setText(String text) {
this.text = text;
whenModelChanges();
}
@Override
public String getText() {
return text;
}
@Override
public void whenModelChanges() {
for (ActionListener listener: actionListeners) {
listener.actionPerformed(null);
}
}
@Override
public void addModelChangesListener(AbstractAction action) {
actionListeners.add(action);
}
}
}您可以使用模拟模型设置此测试,在该模型上设置存根调用,但要明智地这样做,您可能还需要一个模拟操作,这将使事情复杂化,因为该操作是由呈现者创建的。
从本质上测试presenter类中的一行代码,这似乎有很多测试代码,但最大的部分是存根模型,它可能会被真实的模型替换,或者从这个测试类中提取出来并与其他测试共享。
发布于 2012-07-05 23:54:02
在这种情况下,稍微重构一下就能走很长一段路。学会“倾听”测试,并让它们驱动设计。Model只需要知道需要通知ActionListener,它并不关心它是否是AbstractAction。在类契约中尽可能使用最小的接口。以下是用于进行简单测试的重构(可能太简单而不值得进行单元测试,但您已经明白了):
Presenter.class:
public class Presenter {
public Presenter(final IModel model, final IView v) implements ActionListener {
this.model = model;
this.view = v;
model.addModelChangesListener(this);
}
public void actionPerformed(ActionEvent arg0) {
view.setText(model.getText());
}
}IModel.class:
public interface IModel {
public void addModelChangesListener(ActionListener action);
}PresenterTest.class:
@RunWith(MockitoJUnitRunner.class)
public class PresenterTest {
@Mock IView view;
@Mock IModel model;
@Test
public void when_model_changes_presenter_should_update_text() {
when(model.getText()).thenReturn("Test Text");
Presenter p = new Presenter(model, view);
p.actionPerformed(null);
verify(view).setText("Test Text");
}
}https://stackoverflow.com/questions/11286269
复制相似问题