Unit testing with mock objects using mvp4g

330 views
Skip to first unread message

Dennis

unread,
Feb 15, 2010, 5:35:21 AM2/15/10
to Mvp4g
Hi,

I'd like to ask another beginner question to which I could not find an
answer so far: How can I unit test my presenters with mock objects
(using some mocking library like easyMock)? For instance I create a
mock for my view and and model but how do I set everything up now? How
do I inject my mock objects instead of the real ones? Normally mvp4g
would do everything for me (instantiate the proper classes, inject the
dependencies) but now I need to do it manually or am I on the wrong
track here? I'd be very thankful for any advice.

- Dennis

Pierre

unread,
Feb 15, 2010, 8:55:15 AM2/15/10
to Mvp4g
Hi Dennis,

You have to do it manualy. Each presenter has a setter for an eventbus
(public void setEventBus( E eventBus )) and a view (public void
setView( V view )) so that you can inject manually your Mock event bus
and Mock view.

-Pierre

Dennis

unread,
Feb 16, 2010, 5:26:59 AM2/16/10
to Mvp4g
Hi Pierre,

thanks for your answer. If I have to implement the event bus manually
does that mean I cannot test whether the "event flow" (the "wiring" of
the events) is correct, because I have to re-create this in a dummy
event bus?
I try to illustrate this with the following example: I want to test
the bootstrap sequence in my app and check whether everything is
initialized correctly (the presenters receive the init event, do their
init sequence and call the appropriate methods/events on the
RootPresenter to place their views):
- MenuPresenter receives start event
- MenuPresenter does its init operations (e.g. fetching data from the
server, creating data structure, ...)
- MenuPresenter sends RootPresenter.showMenu(Widget) with its view to
display it
(..same for other presenters that contribute...)

-> now I want to check whether RootPresenter.showMenu(widget),
RootPresenter.showTopBar(widget), RootPresenter.showContent(...) has
been called. If I manually wire everything in my dummy event bus ("if
you receive init sent it to P1 and P2, if you receive X sent it
to ...") this test is kind of pointless, isn't it? I could of course
still test whether the Presenters send the correct events.
I know that this might no fall into the definition of a "unit" test
anymore, but somewhere I would want to test that right?

Another more technical question: When implementing my dummy event bus,
what would be a good place/class to start with?

thanks again,

Dennis

Dennis

unread,
Feb 16, 2010, 5:38:36 AM2/16/10
to Mvp4g
Something I forgot to add to my previous post:
When using a mocking library (like easymock) to create mocks for a
presenter I always get the following exception:
java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
at $Proxy11.<clinit>(Unknown Source)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native
Method)
...some lines omitted here..
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:
197)
Caused by: java.lang.UnsupportedOperationException: ERROR:
GWT.create() is only usable in client code! It cannot be called, for
example, from server code. If you are running a unit test, check that
your test case extends GWTTestCase and that GWT.create() is not called
from within an initializer or constructor.
at com.google.gwt.core.client.GWT.create(GWT.java:92)
at com.google.gwt.user.client.ui.UIObject.<clinit>(UIObject.java:179)
... 51 more

I think this is because the view interface exposes The widget class:
public static interface Display extends IView {
// ...
void setMainMenuWidget(Widget w);
}
This is quite bad news for me as I cannot use a mocking library with
mvp4g and have to revert to manual mocking everything again...
Is there a way to fix this?

thanks,

Dennis

Pierre

unread,
Feb 16, 2010, 9:39:46 AM2/16/10
to Mvp4g
Hi Dennis,

> thanks for your answer. If I have to implement the event bus manually
> does that mean I cannot test whether the "event flow" (the "wiring" of
> the events) is correct, because I have to re-create this in a dummy
> event bus?

If you want to test the event bus that is going to be used in your
application, you will have to use GWTTestCase because to create Mvp4g
event bus, you need to call GWT.create and only GWTTestCase manages
it.
However idk if you need to test the call flow because the goal of
Mvp4g is to guarantee this call flow (that's why I tried to have the
whole library covered by Unit tests). I guess testing the created
event bus is usefull if you want to verify your configuration is
correct.

I think the most important thing to cover with unit test it's your
presenter since it's the place where is the business logic.

> I try to illustrate this with the following example: I want to test
> the bootstrap sequence in my app and check whether everything is
> initialized correctly (the presenters receive the init event, do their
> init sequence and call the appropriate methods/events on the
> RootPresenter to place their views):
> - MenuPresenter receives start event
> - MenuPresenter does its init operations (e.g. fetching data from the
> server, creating data structure, ...)
> - MenuPresenter sends RootPresenter.showMenu(Widget) with its view to
> display it
> (..same for other presenters that contribute...)

In one of the example (EmployeeAdmin), I added unit tests to cover the
code. You can see how I implemented a stub event bus to easily verify
if a presenter sends the right event. I haven't modified this example
to integrate Mvp4g 1.1.0 but it will give you a good idea on how to
create a stub event bus.

Pierre

Pierre

unread,
Feb 16, 2010, 9:40:30 AM2/16/10
to Mvp4g
> Something I forgot to add to my previous post:
> When using a mocking library (like easymock) to create mocks for a
> presenter I always get the following exception:
> java.lang.ExceptionInInitializerError
> at java.lang.Class.forName0(Native Method)
> at java.lang.Class.forName(Class.java:169)
> at $Proxy11.<clinit>(Unknown Source)
> at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native
> Method)
> ...some lines omitted here..
> at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunne­r.java:

> 197)
> Caused by: java.lang.UnsupportedOperationException: ERROR:
> GWT.create() is only usable in client code! It cannot be called, for
> example, from server code. If you are running a unit test, check that
> your test case extends GWTTestCase and that GWT.create() is not called
> from within an initializer or constructor.
> at com.google.gwt.core.client.GWT.create(GWT.java:92)
> at com.google.gwt.user.client.ui.UIObject.<clinit>(UIObject.java:179)
> ... 51 more
>
> I think this is because the view interface exposes The widget class:
> public static interface Display extends IView {
> // ...
> void setMainMenuWidget(Widget w);
> }
> This is quite bad news for me as I cannot use a mocking library with
> mvp4g and have to revert to manual mocking everything again...
> Is there a way to fix this?
One way to solve this issue it's to have remove any link to Widget
class (or any class that inherits Widget) and replace it by a widget
interface:

public interface MyWidgetInterface {

public Widget getMyWidget();

}

public static interface Display extends IView {
// ...

void setMainMenuWidget(MyWidgetInterface w);
}

public static interface DisplayImpl implements IView... {

void setMainMenuWidget(MyWidgetInterface w){
setWidget(w.getWidget);
}
}

The EmployeeAdmin example shows you how this WidgetInterface can be
used.

Hope this help,
Pierre

Dennis

unread,
Feb 16, 2010, 1:34:56 PM2/16/10
to Mvp4g
thanks a lot for the pointer to the employeeAdmin example, of course
the ones I looked at didn't have tests ;-)
I added another level of indirection by adding the WidgetInterface you
suggested and it works! Although I don't really know why,because the
reference to Widget is still in the WidgetInterface...it seems to be
related to the way easyMock creates those mock objects, or is there
another explanation?
I'll have a more intensive look at the testing tomorrow and will
report my findings ;-)

thanks,

Dennis

Dennis

unread,
Feb 17, 2010, 4:38:32 AM2/17/10
to Mvp4g
I tried to implement a MockEventBus but this class seems to have
drastically changed in 1.1.0: Instead of triggering an event by
calling a unique user defined method (e.g.
myEventBus.changeCenterScreen) to fire events there was a central
dispatch method that uses string constants to identify events (e.g.
myEventBus.dispatch("changeCenterScreen")). And The EventBus class has
been refactored to an interface which only contains history stuff, the
whole rest seems to be generated by the framework.
So in order to write a mock event bus and always store the last event
(as in the employeeAdmin example) I need to do the following:

public class MockEventBus implements MyEventBus {

public void changeCenterScreen(IWidget w) {
collect("changeCenterScreen, w)
}

public void expandMainMenuItem(MAIN_MENU_ITEM_TYPES mainMenuItemType)
{
collect("expandMainMenuItem", mainMenuItemType)
}

public void setMainMenuWidget(Widget w) {
collect("setMainMenuWidget", w);
}

/* same code for all my events ... /*

public void collect(String event, Object data) {
lastEvent = event;
lastEventData = data;
}
}
(The collect method is similar to the old "dispatch" method. This
requires the user )

For me this seems not very practical:
- I have to interhit from my EventBus inteface because all the
presenters are parametrised with it. Whenever a new event is added I
have to adapt the MockEventBus with the same repeting boilderplate
code over and over again
- I have to come up with some string mapping for the events, manually,
which feels like going back to 1.0...and error prone too

So I am wondering if there is better, more practical solution for this
problem?

thanks,

Dennis

Pierre

unread,
Feb 17, 2010, 8:52:18 AM2/17/10
to Mvp4g
Hi Dennis,

> - I have to interhit from my EventBus inteface because all the
> presenters are parametrised with it. Whenever a new event is added I
> have to adapt the MockEventBus with the same repeting boilderplate
> code over and over again

Unfortunately, I don't think there is a better way. Your presenter
knows only your event bus interface so you have no other choice than
implementing it. It can seem repeting but for an event, you just have
to add 3 lines of codes in your Mock event bus. The good thing with an
interface, you will see a compilation error whenever you add your
event so that you will know right away to add it to your Mock event
bus.

> - I have to come up with some string mapping for the events, manually,
> which feels like going back to 1.0...and error prone too

Since you're doing test, if you don't map your events the right way in
your mock, you should see it right away in your assert statement.
Maybe you could create a Mock this way:

public class MockEventBus implements MyEventBus {

private boolean changeCenterScreenExpected;
private boolean expandMainMenuItemExpected;

private Object eventData;

public void changeCenterScreen(IWidget w) {
assertTrue(changeCenterScreenExpected);
assertEquals(eventData, w);
changeCenterScreenExpected = false;
}

public void expectchangeCenterScreen(IWidget w){
changeCenterScreenExpected = true;
this.eventData = eventData;
}

/* same code for all my events ... /*

}

It's more code but it's no risk of mapping error.

For right now, I can't think of a better way. Can't you mock your
event bus with a Mock library like jMock? I haven't looked at it yet
but it may work.

If I come up with a better solution, I will let you know or let me
know if you find something easier to implement.

Thanks,
Pierre

> > > Pierre- Hide quoted text -
>
> - Show quoted text -

Dennis

unread,
Feb 17, 2010, 12:03:58 PM2/17/10
to Mvp4g
Hi Pierre,

I was successful in mocking the event bus with easyMock and then I can
do the same testing as you showed in the manual example (Expect events
and event data and verify afterwards).

The drawback is that the event bus is then completely passive (it
doesn't send any events, it just receives them and doesn't notify any
event handlers) and the whole event logic is "lost", e.g. when you
want to test a more complex scenario involving multiple events that
are triggered. With the current version you just have to re-create the
wiring manually. Or am I seeing something wrong here?

Pierre

unread,
Feb 17, 2010, 10:09:49 PM2/17/10
to Mvp4g
Hi Denis,

> I was successful in mocking the event bus with easyMock and then I can
> do the same testing as you showed in the manual example (Expect events
> and event data and verify afterwards).

Nice, would you mind posting your code? I'm interesting in seeing how
you did it and it may also help other people with the same problem.

>
> The drawback is that the event bus is then completely passive (it
> doesn't send any events, it just receives them and doesn't notify any
> event handlers) and the whole event logic is "lost", e.g. when you
> want to test a more complex scenario involving multiple events that
> are triggered. With the current version you just have to re-create the
> wiring manually. Or am I seeing something wrong here?

Creating a fake event bus to reproduce the event logic is not really
useful. Just tests your handler one by one. You would have the same
result as if your event bus reproduces the event logic.
Instead of :

public void testEvent1(){
eventbus.event1(sthg);
verifyGoodTreatmentForEvent1(handlerA);
verifyGoodTreatmentForEvent1(handlerB);
verifyGoodTreatmentForEvent1(handlerC);
}

you can have:

public void testEvent1HandlerA(){
handlerA.onEvent1(sthg);
verifyGoodTreatmentForEvent1(handlerA);
}

public void testEvent1HandlerB(){
handlerB.onEvent1(sthg);
verifyGoodTreatmentForEvent1(handlerB);
}

public void testEvent1HandlerC(){
handlerC.onEvent1(sthg);
verifyGoodTreatmentForEvent1(handlerC);
}
This way you don't have to change your unit tests even if you change
your event bus logic. After if you want to test a scenario with
multiple events, JUnit may not be what you need as you're not doing
unit testing anymore.

Thanks,
Pierre

Dennis

unread,
Feb 20, 2010, 9:40:01 AM2/20/10
to Mvp4g
Hi Pierre,

I totally agree with you that those kind of tests that test the event
flow would no longer be unit tests (they involve multiple presenters
and views etc). I still think such tests will be needed. Would it be
possible at all? Is anybody doing it?

Here's how I test my presenter with easymock (this does the same as
described by Pierre above):
- Make sure that the event bus interface contains no references to gwt
ui classes otherwise I get the "ERROR: GWT.create() is only usable in
client code(...)" error. E.g. wrap all references to Widget in an
interface that contains a "public Widget getMyWidget()" method
- Create a unit test for every presenter:
Setup the mocks in the setup() method:
@Before
public void setUp() throws Exception {
viewMock = createMock(ProfilePresenter.Display.class); // A mock for
the view interface
eventBusMock = createMock(MonoEventBus.class);

/* setup the presenter with its view and event bus */
presenter = new ProfilePresenter();
presenter.setView(viewMock);
presenter.setEventBus(eventBusMock);
}

then you can test every event as follows. In the following simple
example we have a presenter that is responsible for some user profile
page:
@Test
public void testOnShowProfileScreen() {
String testName = "John Doe";

/* record expectations for all mocks */
viewMock.setName(testName);
IWidget mockProfileWidget = createMock(IWidget.class);
expect(viewMock.getViewWidget()).andReturn(mockProfileWidget);
eventBusMock.changeCenterScreen(mockProfileWidget); // this event
should be fired to display the profile page

replayAll();

/* do the test */
presenter.onShowProfileScreen(testName);

/* verify mocks */
verifyAll();
}

btw. is there a way here to nicely format code?

Pierre

unread,
Feb 20, 2010, 5:51:10 PM2/20/10
to Mvp4g
Hi Denis,

Thanks for your code. It's nice to know that you can easily mock a
Mvp4g event bus.

> I totally agree with you that those kind of tests that test the event
> flow would no longer be unit tests (they involve multiple presenters
> and views etc). I still think such tests will be needed. Would it be
> possible at all? Is anybody doing it?

Since those kind of tests are integration tests, shouldn't use an
integration tool like selenium?
The thing is to do those types of test you need to generate Mvp4g
event bus, which mean using GWT.create, so you need GWTTestCase. Even
if you do that, then to start your tests and verify your result, you
need to have access to presenters/views generated by Mvp4g and this is
not possible now.

> btw. is there a way here to nicely format code?

None that I'm aware of, but it would be a nice functionnality.

Pierre

matt

unread,
Jun 16, 2011, 5:10:54 AM6/16/11
to mv...@googlegroups.com
Hi All,

I know this is an old thread but wanted to post an update as I just ran into the same issue today, and this was the first hit on Google I found which suggests it is not possible.

Using JMock, I wanted to generate a mock of my event bus in order to inject it into an event handler.  This caused the following error:

java.lang.ExceptionInInitializerError

                at java.lang.Class.forName0(Native Method)

                at java.lang.Class.forName(Class.java:169)

                at $Proxy6.<clinit>(Unknown Source)

                at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

                at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)

                ......                at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)

                at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Caused by: java.lang.UnsupportedOperationException: ERROR: GWT.create() is only usable in client code!  It cannot be called, for example, from server code.  If you are running a unit test, check that your test case extends GWTTestCase and that GWT.create() is not called from within an initializer or constructor.

                at com.google.gwt.core.client.GWT.create(GWT.java:92)

                at com.google.gwt.user.client.ui.UIObject.<clinit>(UIObject.java:188)

                ... 35 more

The reason for this as you have already suggested here is because some of the methods on the event bus accept Widgets. There is however a fix for this that can be done using GWTMockUtilities.disarm() prior to running your test.  More detail for this is explained here: http://blog.danielwellman.com/2009/02/mocking-gwt-widgets-with-gwtmockutilities.html

public class EventHandlerTests {

    private final Mockery context = new JUnit4Mockery() {{

        setImposteriser(ClassImposteriser.INSTANCE);

    }};

    @Before

    public void disableWidgets() {

        GWTMockUtilities.disarm();

    }

    @After

    public void reEnabledWidgets() {

        GWTMockUtilities.restore();

    }

    ... test methods here..

}

Note to eclipse users - if you get the following exception:

java.lang.SecurityException: class "org.hamcrest.TypeSafeMatcher"'s signer information does not match signer information of other classes in the same package

I believe it is because Eclipse provides a signed version of org.hamcrest.core as part of it's JUnit 4 library which conflicts with the jar's you download from the JMock site.  To fix this, make sure the unsigned jar's appear BEFORE JUnit 4 in the classpath.

More info here:

http://code.google.com/p/hamcrest/issues/detail?id=128

Hope this helps someone.

Matt

 

Reply all
Reply to author
Forward
0 new messages