Write a Mockito test for the presenter class (first presenter sample)

I am trying to get to know TDD and the first Presenter template. Right now I am stuck writing a test case for my Presenter.class. My goal is to cover the entire Presenter.class class, including Event Action, but I don't have any glue how to do this with 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() { } } 

Thanks in advance!

+4
source share
3 answers

First ... thanks guys!

After a while, I realized this solution and stuck to it because I did not want to implement any interfaces in the presenter class, and I did not want to create stub classes in my tests.

Iview

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

IModel

 public interface IModel { public String getText(); public void addModelChangeListener(Action a); } 

Leading

 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"); } } 
+1
source

In this situation, the connection between the model and the presenter is fairly free (passing through the action listener), which is probably why you should not use the model layout.

You can use the real model (I would prefer that if the real model is simple enough), or, as I said in the fragment below, make a stub inside the test code.

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

You may be able to customize this test using a mock model on which you set up stub calls, but for this reasonably, you may also need a mock action that will complicate the situation, as the action is created by the facilitator.

This looks like a lot of test code for testing essentially one line of code in a presenter class, but the biggest snippet is a stub model, which can be replaced with a real model or retrieved from this test class and other tests are shared.

0
source

This is the case when a little refactoring can go a long way. Learn to listen to tests and let them control the design. Model only needs to know that it needs to report an ActionListener notification, no matter if it is an AbstractAction . Use minimal interfaces in your contracts. Here is refactoring to make a simple test (perhaps too simple to cost unit testing, but you get the idea):

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

All Articles