为演示器类编写模拟测试(演示者第一模式)



我正在尝试熟悉TDD和演示者第一模式。现在,我正在为我的演示者编写测试用例.class。我的目标是涵盖整个演示者.class包括动作事件,但我没有胶水如何使用 Mockito。

主讲人.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());
        }
    });
}}

四.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);
}

演示者测试.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() {
    }
}

提前感谢!

起初...谢谢你们!

过了一会儿,我想出了这个解决方案并坚持了下来,因为我不想在演示器类中实现任何接口,也不想在我的测试中创建存根类。

、四

public interface IView {
    public void setText(String text);
}

伊莫德尔

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());
            }
        });
    }
}

演示者测试

@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");
    }
}

在这种情况下,模型和演示器之间的连接足够松散(通过操作侦听器进行通信),因此最好不要对模型使用模拟。

您可以使用真实的模型(如果真实模型足够简单,我更喜欢这样),或者像我在下面的代码片段中所做的那样,在您的测试代码中创建一个存根。

@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);
        }
    }
}
您可以使用模拟模型设置

此测试,您可以在该模型上设置存根调用,但要明智地执行此操作,您可能还需要一个模拟操作,这将使事情复杂化,因为操作是由演示者创建的。

这似乎是很多测试代码,用于测试演示器类中的一行代码,但最大的块是存根模型,它可能会被真实模型替换或从该测试类中提取并与其他测试共享。

在这种情况下,

一点点重构可以走很长的路。 学会"倾听"测试,让它们推动设计。 Model只需要知道需要通知ActionListener,它不在乎它是否是AbstractAction。 在类协定中使用尽可能小的接口。 以下是进行简单测试的重构(可能太简单了,不值得进行单元测试,但你明白了):

主讲人.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);
}

演示者测试.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");
    }
}

相关内容

  • 没有找到相关文章

最新更新