Search code examples
javagwtgwtmockito

GwtMockito - click handlers for many buttons


I have problem with GwtMock and click handlers.

In my unit test I have a field with ClickHandler and Button:

@GwtMock private ClickHandler clickHandler;

My setUp method looks like:

@Before
public void setUp() {
    when(this.display.getClearButton()).thenReturn(this.button);
    when(this.display.getChangeStatusButton()).thenReturn(this.button);
}

And my test looks like:

@Test
    public void shouldClearFilterAfterClickClearFilterButton() {
        // given
        when(this.button.addClickHandler(any(ClickHandler.class))).thenAnswer(new Answer<Object>() {
            public Object answer(InvocationOnMock aInvocation) throws Throwable {
                clickHandler = (ClickHandler) aInvocation.getArguments()[0];
                return null;
            }
        });

        this.presenter = new PresenterImpl(this.display, this.messages);

        // when
        clickHandler.onClick(clickEvent);


        // then
        this.presenter.asWidget();

    }

Code which I would like to test looks like (I call this method from contructor):

private void addHandlers() {



    this.display.getClearButton().addClickHandler(new ClickHandler() {
                @Override
                public void onClick(ClickEvent event) {
                    clearFilter();
                }
            });
            this.display.getChangeStatusButton().addClickHandler(new ClickHandler() {
                @Override
                public void onClick(ClickEvent event) {
                    changeStatus();
                }
            });
        }

The problem is that when I run a unit test I make a click event on button "ChangeStatus" but I want make a click event on button "Clear"

What is interesting when I change order of declaration handler then I can invoke code over the "Clear" button

How to solve this problem? How to call click event on particular buttons?


Solution

  • Let's read that code together:

    1. whenever getClearButton() or getChangeStatusButton() is called, return this.button; that is, the very same button for both method calls, which means you won't be able to tell which is which: it's just the same.
    2. whenever addClickHandler is called on that mock button, store the click handler in a field; that is, if addClickHandler is called twice, the second call will overwrite the field with the second click handler, and you'll no longer reference the first one.
    3. code under test calls both getClearButton() and getChangeStatusButton() and calls addClickHandler on both; that is, calls addClickHandler twice on this.button.

    The problem is that when I run a unit test I make a click event on button "ChangeStatus" but I want make a click event on button "Clear"

    What is interesting when I change order of declaration handler then I can invoke code over the "Clear" button

    Yes, that's exactly the expected behavior given your code. Use distinct mock buttons if you want to tell the buttons apart.


    IMO, a better approach would be to, either: * make getClearButton and getChangeStatusButton return HasClickHandlers, so you don't even need GwtMockito and can just use bare Mockito. * refactor your code so that the view adds click handlers, the presenter is passed to the view, and the view can thus call presenter methods from the click handlers (e.g. presenter.clear() and presenter.changeStatus()). For your presenter tests you can thus just call the presenter methods. Again, you no longer need gwtMockito and can just use bare Mockito. See http://www.gwtproject.org/articles/mvp-architecture-2.html

    AFAICT, GwtMockito is more suited to cases where you don't separate your view and presenter in code, and rather use UiBinder with the Java class playing the role of the presenter, and the .ui.xml being the view.