Testing GWTP presenter with asynchronous calls
Asked Answered
T

3

7

I'm using GWTP, adding a Contract layer to abstract the knowledge between Presenter and View, and I'm pretty satisfied of the result with GWTP. I'm testing my presenters with Mockito.

But as time passed, I found it was hard to maintain a clean presenter with its tests. There are some refactoring stuff I did to improve that, but I was still not satisfied.

I found the following to be the heart of the matter : My presenters need often asynchronous call, or generally call to objects method with a callback to continue my presenter flow (they are usually nested).

For example :

  this.populationManager.populate(new PopulationCallback()
  {
     public void onPopulate()
     {
        doSomeStufWithTheView(populationManager.get());
     }
  });

In my tests, I ended to verify the population() call of the mocked PopulationManager object. Then to create another test on the doSomeStufWithTheView() method.

But I discovered rather quickly that it was bad design : any change or refactoring ended to broke a lot of my tests, and forced me to create from start others, even though the presenter functionality did not change ! Plus I didn't test if the callback was effectively what I wanted.

So I tried to use mockito doAnswer method to do not break my presenter testing flow :

doAnswer(new Answer(){
     public Object answer(InvocationOnMock invocation) throws Throwable
     {
        Object[] args = invocation.getArguments();
        ((PopulationCallback)args[0]).onPopulate();
        return null;
     }
 }).when(this.populationManager).populate(any(PopulationCallback.class));

I factored the code for it to be less verbose (and internally less dependant to the arg position) :

doAnswer(new PopulationCallbackAnswer())
  .when(this.populationManager).populate(any(PopulationCallback.class));

So while mocking the populationManager, I could still test the flow of my presenter, basically like that :

@Test
public void testSomeStuffAppends()
{
  // Given
  doAnswer(new PopulationCallbackAnswer())
  .when(this.populationManager).populate(any(PopulationCallback.class));

  // When
  this.myPresenter.onReset();

  // Then
  verify(populationManager).populate(any(PopulationCallback.class)); // That was before
  verify(this.myView).displaySomething(); // Now I can do that.
}

I am wondering if it is a good use of the doAnswer method, or if it is a code smell, and a better design can be used ?

Usually, my presenters tend to just use others object (like some Mediator Pattern) and interact with the view. I have some presenter with several hundred (~400) lines of code.

Again, is it a proof of bad design, or is it normal for a presenter to be verbose (because its using others objects) ?

Does anyone heard of some project which uses GWTP and tests its presenter cleanly ?

I hope I explained in a comprehensive way.

Thank you in advance.

PS : I'm pretty new to Stack Overflow, plus my English is still lacking, if my question needs something to be improved, please tell me.

Theomorphic answered 6/12, 2012 at 10:36 Comment(0)
F
1

You could use ArgumentCaptor:
Check out this blog post fore more details.

Firebrand answered 7/12, 2012 at 9:42 Comment(0)
P
0

If I understood correctly you are asking about design/architecture.

This is shouldn't be counted as answer, it's just my thoughts.

If I have followed code:

    public void loadEmoticonPacks() {
    executor.execute(new Runnable() {
        public void run() {
            pack = loadFromServer();
            savePackForUsageAfter();
        }
    });
}

I usually don't count on executor and just check that methods does concrete job by loading and saving. So the executor here is just instrument to prevent long operations in the UI thread.

If I have something like:

accountManager.setListener(this);
....
public void onAccountEvent(AccountEvent event) {
....
}

I will check first that we subscribed for events (and unsubscribed on some destroying) as well I would check that onAccountEvent does expected scenarios.

UPD1. Probably, in example 1, better would be extract method loadFromServerAndSave and check that it's not executed on UI thread as well check that it does everything as expected.

UPD2. It's better to use framework like Guava Bus for events processing.

Pleasance answered 7/12, 2012 at 13:8 Comment(0)
K
0

We are using this doAnswer pattern in our presenter tests as well and usually it works just fine. One caveat though: If you test it like this you are effectively removing the asynchronous nature of the call, that is the callback is executed immediately after the server call is initiated.

This can lead to undiscovered race conditions. To check for those, you could make this a two-step process: when calling the server,the answer method only saves the callback. Then, when it is appropriate in your test, you call sometinh like flush() or onSuccess() on your answer (I would suggest making a utility class for this that can be reused in other circumstances), so that you can control when the callback for the result is really called.

Kessiah answered 21/4, 2013 at 6:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.