3

In tutorials on GWT Google uses to different approaches to do MVP, either the View specifies the Presenter or the Presenter specifies the View. The first one is used when using Activities and Places.

This post touches on this subject: MVP: Should the View implement a Presenter's interface or vice versa?

However I would like to know which alternative you think is best when it comes to unit testing of the presenter and the view? Or will both work equally well?

Community
  • 1
  • 1
per_jansson
  • 2,103
  • 4
  • 29
  • 46

3 Answers3

4

The idea behind unit testing of presenter is to mock the view, and write several assertions against state of this mocked view, which would be represented visually in the real life app. Thanks to such an approach there is no need for running full GWTTestCase, which takes a lot of time and should be rather put in the category of integration testing, not unit testing.

If you would try both MVP approaches, the unit tests could look like:

MVP 1:

@Test
public void shouldAddContactOnAddContactClicked() {
    // given
    ContactsPresenter.Display display = mock(ContactsPresenter.Display.class);
    MockButton addButton = new MockButton();
    given(display.getAddButton()).willReturn(addButton);
    ContactsDisplay.Presenter presenter = new ContactsPresenter();
    presenter.bindView(display);
    presenter.setContacts(new ArrayList<Contact>());

    // when
    addButton.click();

    // then
    verify(display).addContact(any());
    assertThat(presenter.getContacts().size(), is(1));
}

Where the MockButton is something I described here: Comprehensive Pros/Cons of Mocking Frameworks for GWT

Although possible, it is not really convenient to mock things this way. The MVP2 approach seems to perform better:

@Test
public void shouldAddContactOnAddContactClicked() {
    // given
    ContactsView view = mock(ContactsView.class);
    ContactsView.Presenter presenter = new ContactsPresenter();
    presenter.bindView(view); // assuming that presenter will call view.setPresenter(this)
    presenter.setContacts(new ArrayList<Contact>());

    // when
    presenter.onAddContactClicked();

    // then
    verify(view).addContact(any()); 
    assertThat(presenter.getContacts().size(), is(1));
}

Another reason for using the second approach is the problem in MVP1 with declaring elements of the display, which would trigger different events (e.g. ClickEvent, FocusEvent). MVP2 also makes things easier when it comes to UiBinder.

Community
  • 1
  • 1
morisil
  • 1,345
  • 8
  • 19
  • Thank you very much! Can you please describe more in detail what you mean in the last sentence about the problems declaring elements of the display for triggering events in "MVP1" and how the UiBinder suits "MVP2" better? – per_jansson May 01 '11 at 07:05
  • Imagine `Display` where you have `getAddButton()` method which should return type implementing both `HasClickHandlers` and `HasAllTouchHandlers`. It is possible to go with generics like `` but it reveals to be very inconvenient later on, and not really better than explicit casting. We can also define additional `getAddButtonTouch()` method, but such an approach seems very counterintuitive to me. – morisil May 01 '11 at 08:00
  • So what you are saying basically is that if GUI elements have more than one purpose and should trigger different actions in the Presenter it is easier and more clear to use a UiHandler in the View which delegates to different methods in the Presenter? – per_jansson May 01 '11 at 08:07
  • `UiBinder`: in fact it introduces a lot of logic into view, which would be put in presenter otherwise, especially if you use editors and drivers. I switched my codes to MVP2 and I use `UiHandler` to "push" events into presenter instead of pulling event handlers in the presenter. It saves some boilerplate code and as Thomas suggested you can reuse view, which would be quite hard in MVP1. Note: I create drivers and editors in the view, but then expose them to the presenter. – morisil May 01 '11 at 08:08
  • Thanks. Do you have an opinion on if MVP2 really is MVP or if it breaks some of the "contracts" by making the View aware of the Presenter and also having the View specifying the Presenter, which one answer here http://stackoverflow.com/questions/3309029/mvp-should-the-view-implement-a-presenters-interface-or-vice-versa by Shahzeb states? – per_jansson May 01 '11 at 08:28
  • At first I was quite disappointed by MVP2 for the "religious" reasons. Later on I realized that we can define things differently. View is static, for example defined as `ui.xml`. Then we have java file related to such a view - this is a kind of "visual logic", currency formatter would fit here, editor structure, and driver initialization (automatic copying of model onto view) would fit here as well. Then we have presenter which interacts with "visual logic" - deals with domain model, events, remote services, works on drivers and editors. I use GIN to bind everything. Not a clear MVP, but works – morisil May 01 '11 at 15:58
  • As you can see it could be defined as presenter split into too, where one is called "display" or "view", and should be in fact named "visual logic". – morisil May 01 '11 at 16:00
3

Avoid using HasXxxHandlers, i.e. use the approach from the part 2 article where each peer has a reference to the other. HasXxxHandlers are far too complicated to mock, particularly when using mocking libraries such as Mockito or EasyMock. For best testability, you'd inject the view into the presenter and the presenter would then call a setPresenter or setDelegate method of the view (that way, you can unit test that you correctly call that method, at the right time). When using Activities, where your activity is a presenter, you'll likely call view.setPresenter(this) in start and view.setPresenter(null) in onStop and onCancel; that way you can have a singleton view shared with several presenters (though no more than a single one at a time, obviously).

Thomas Broyer
  • 64,353
  • 7
  • 91
  • 164
  • Thank you very much! Can you please describe more in detail what you mean when you say that HasXxxHandlers are far too complicated to mock? – per_jansson May 01 '11 at 07:06
  • Mocking a view with a `HasClickHandlers getSaveButton()` involves: mocking the `HasClickHandlers`, which should capture the `ClickHandler` given as argument to `addClickHandler`; if you ever remove your handler, then you'll have to return a new `HandlerRegistration` from your mocked `addClickHandler` and add the appropriate `verify`/`assert` on its `removeHandler` method, which means keeping a reference to it in your test code. Firing an event means mocking a `ClickEvent`. Contrast that with mocking a view that captures the delegate/presenter passed to its setter and calls `saveClick` on it. – Thomas Broyer May 02 '11 at 15:59
0

Unit-test-wise, it really doesn't matter. If you design it right, it is just a matter of where you need a stub (or mock) injected. The unit test should not be allowed to dictate design decisions. However, a unit-test will often indicate if a design is wrong (such as missing injection etc.)

Morten
  • 3,778
  • 2
  • 25
  • 45