Search code examples
unit-testinggwtviewmvppresenter

In a unit test perspective: should the view specify presenter or the other way around in GWT MVP?


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?


Solution

  • 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.