Nov 7, 2013

Testing GWT with GwtMockito

Introduction

This article shows how to use Mockito’s doAnswer() and thenAnswer() to test hard to reach code usually written within a GWT application. The technique of calling anonymous inner classes from test code applies to pure Java tests as well. In order to make Mockito work with GWT, GwtMockito is used. If you are not familiar with the basic usage of Mockito, I recommend writing some standard Mockito tests first.

When it comes to unit testing GWT Applications, there is a lot of pain and frustration. While GWT in written in Java (well mostly java), it is compiled into JavaScript and needs a JavaScript engine to execute. Furthermore, some low-level GWT code is written directly in JavaScript, and cannot be executed as Java. How did GWT manage to put native JavaScript within their Java code? The trick is that GWT embeds the code within comments following a native method. Since the method is native, the java compiler will handle this gracefully (it assumes the contents of the method will be provided at run-time via a shared library). However, since GWT doesn’t run in a JVM, this is never a problem. You will find their are times you will want to write native JavaScript for your GWT applications as well, but it is rare (or at least it should be). If you want to test any of the JavaScript code, GwtMockito is not the solution; you would need to use GWTTestCase instead.

I am not sure if I find the technique of embedding JavaScript intriguing, ingenious, or hideous (it probably depends on the day). When you cannot track down a GWT issue, due to it being well hidden in the generated JavaScript, I find it hideous. When I can debug my browser with breakpoints handled in my IDE, I find it ingenious.

When it comes to running tests, GWT provides a TestCase framework that runs within Jetty container, allowing for the native JavaScript code to be executed within a JavaScript engine. Unfortunately, these tests are slow; it takes a while for the Jetty container to start up and Java code is compiled into JavaScript before executing. If you write a lot of tests, this approach is not scaleable; personally, I like my continuous integration machine to be able to compile, generate artifacts, and run tests within minutes.

Please download GWT Mockito from GitHub. Please download Mockito from Google Code (the single “all” jar is the easiest way to go).

GWT Testing Options

  1. GWTTestCase
  2. While, this is the best way to test all GWT code, including the native JavaScript code; it comes with a cost. Execution time of each test class is quite high. Running the tests in an IDE has also be a challenge. In Eclipse, I had to separate my GWTTestCase tests into a separate source folder, since they couldn’t be executed with traditional test classes at the same time.

    When we first started on our GWT Application and this was the given solution for testing our GWT code, it had a negative impact to development timeline, test coverage, and general happiness of the developers. We quickly moved to a mixed solution to where we used this as minimally as possible. Currently, we have no GWTTestCase unit tests. We do have a rather extensive end-to-end tests using written by the QA team, so our application does get tested with the production generated JavaScript; just not from our unit tests.

  3. Mockito
  4. Mockito cannot handle final classes, final methods, static methods, and native methods. In order to use straight Mockito with GWT, you have to craft your code keeping good separation from your business logic and GWT components. While decoupling is a good thing, decoupling due to a limitation on a testing strategy can be frustrating. It still doesn’t solve the problem of testing a lot of your UI code. I was able to write MVP code and test the presenter and model code with just using Mockito, but the view code couldn’t be tested this way. When writing tests with straight Mockito, you will want to leverage the GWT provided utility method GWTMockUtilities.disarm(). This will make GWT.create() return NULL whenever it is called. This helps prevent loading of some of the native GWT classes that have native, static, or final methods in them; mileage will vary.

    When we added mockito to our testing strategy, general happiness of the developers improved, but only slightly. We still had a lot of tests that couldn’t be written, and a lot of hoops were done to try to make classes testable.

  5. Easmock
  6. Easymock has the same limitations as Mockito. Prior to my days of doing GWT development, I used Easymock. Over the past two years, I have used Mockito. If I had a choice, and didn’t have other dependencies requiring me to use one over the other, I would choose Mockito. There are many articles out there comparing them and discussing their differences, they do a better job than I would explaining it, and are worth reading.

  7. PowerMockito
  8. With PowerMockito, bytecode manipulation can be done prior to class being loaded. Thus, it can handle final classes and methods, static methods, and native methods. However, a fair amount of setup for each test case is needed. Start up time for running a test is slower than a straight Mockito JUnit test (no surprise with all of the byte code manipulation that needs to be done). From my testing, every Powermock test required a minimum 0.5 seconds of additional time to execute than a standard JUnit test. While an additional 0.5 seconds / test class doesn’t sound like a lot, it does add up. If you have 240 tests, that is an additional 2 minutes to execute your test suite. Performance isn’t the only reason to avoid Powermock; a variety of tricks are needed to mock all of the static, native, final methods which takes time. Once you have a few written, patterns do form and writing additional tests should become easier.

    Prior to using GwtMockito, we had one to two hundred PowerMockito tests. After adopting GwtMockito, many have been rewritten (and rather quickly as well). We currently are down to around twenty; due to time or difficulty to rewrite them. If/when that code is re-evaluated, our plan is to rewrite the unit test using GwtMockito.

  9. GwtMockito
  10. GWT Mockito is an extension to Mockito. It provides a classloader that will do byte code manipulation to strip away the static/final/native modifiers to classes and methods, so you can actually use mockito on them (similar to what PowerMockito does, but with less options). It actually does the same trick I did for mocking final classes/methods in unit tests . It just takes it to the next level doing all of the work with GWT for you to make it work with Mockito.

    We have been using GwtMockito for about 6 months now, and the entire GWT development team prefers writing them over PowerMockito and GwtTestCase tests.

Overview

I am going to use an example to show I test areas in GWT that I have found to be difficult to test. For this article, I’m using the GWT Sample Application as my starting point. Hopefully, that makes it easier for focus on the testing, and not on the sample application; if you are a GWT developer, I’m guessing you have built the sample application at least once.

The following application does a simple server request and displays the result of the server back on the screen. In addition to the sample application, I have also added a GWT SimpleEventBus to communicate between two components. In a real application, you would expect this to be done between two different components. For demo purposes, however, the firing and listening of the event are both done within this same component.

Example Code

Here is the example code we are going to test. I want to be able to test the onSuccess() async callback and the onClick method in the anonymous inner class [ the closest thing Java 1.7 has to a closure 🙁 ].

Accessing the Mocking GWT Widgets within your component

When you use the GwtMockitoTestRunner, the GWT.create() method will return Mockito mocked objects. If you want access to those mocks from your test case, simply annotate a member variable with @GwtMock.

    @GwtMock
    private Button button;

By default GwtMockito, GWT.create() will return the same Mockito mocked object for each type. Using the @GwtMock annotation the test runner will inject the same mocked instance it will return for GWT.create() calls into that member variable. If you don’t need to add any when/verify calls to the mocked object, you may not need to add the annotated member to the class (it is mocked regardless).

More control with GWT.create()

If you want GWT.create() to return a non mocked object, or you want to have it create a new mock for every call, then you can use GwtMockito.useProviderForType(). This gives you full control over what GWT.create() returns. GWT’s SimpleEventBus is 100% Java code and can be used within JUnit, so it is a good example of a GWT class you can use directly in your tests (instead of a mock). By default, GwtMockitoTestRunner causes GWT.create() to return Mockito mocked objects unless there is a provider registered with GwtMockito.useProviderForType() for a given class.

Now, my unit test uses an actual instance of SimpleEventBus, even though it is created by GWT.create().

So far we have:

  1. Created a JUnit test class with the GwtMockitoTestRunner.
  2. Have a reference to the GWT Button Mockito instance in the test class (by annotating it with @GwtMock).
  3. Have GWT.create(SimpleEventBus.class) return an actual SimpleEventBus instance (by creating a provider).

Now it is time to start writing our test.

Testing Event Code in Anonymous Inner Classes

With GWT code, especially in your view code, you will have a fair amount of anonymous inner classes for handling events. How do you execute that code from your unit tests?

Now that you have GWT.create() behaving the way you want, you can use those mocks to your advantage. For example, in the constructor of SampleApplication, a click handler is registered to a button. If that button is a Mockito mock object, I can gain access to that handler.

To gain access to that anonymous inner class, use Mockito’s Mockito.when().thenAnswer(). Just make sure the Mockitio.when().thenAnswer() is done prior to the anonymous inner class being created.

By the time SampleApplication is constructed, GWT.create(Button.class) will return a Mockito mocked object. When button.addClickHandler() is called, we tell Mockito to answer that call. We then have access to the arguments passed into addClickHandler; hang onto a reference to the click handler, and then use it from the test method.

To execute the given inner class business logic, just call clickHandler.onClick(new ClickEvent(){}); from our unit test.

This use of thenAnswer() is standard Mockito functionality; it is not part of GwtMockito. Reminder, make sure your Mockito.when().thenAnswer() is setup before the class you are testing is initialized.

Executing Async Callback onSuccess() and onFailure() Methods

To mimic a response (and to handle async callbacks) you use the Mockito functionality of Mockito.doAnswer().when().

For the SampleWidget, we want onSuccess() to be called when the server call is requested. Since the service is a mocked object, we can tell Mockito to do a given answer when the method is called. Within the doAnswer(), we access the AsyncCallback instance (usually a private variable or anonymous inner class, but that doesn’t matter to our test) and invoke the onSuccess() method immediately. We mock the server with a success return and then have it invoke the onSuccess() code for us.

The mocking allows for the onSuccess() (or onFailure()) method to be called so the business logic is executed. In the unit test, the response will not actually be asynchronous, but this is sufficient for testing the behavior of a successful service call. Use integration or system tests for testing behavior of the application in a more production like scenario.

Putting it all together

In SampleWidget we want to verify that the widget behaves correctly, when the button is clicked. We want the business logic of the button to be invoked and we want the async callback response business logic to be invoked. We want to verify that the SampleWidget will then update the UI components based on the response from the server.

This was done following 4 steps:

  1. Setup unit test using GwtMockitoTestRunner.
  2. Get GWT.create() to return the appropriate mock or class using @GwtMock and GwtMockito.useProviderForType().
  3. Use Mockito.when().thenAnswer() to gain access to anonymous inner classes so you can invoke that business logic.
  4. Use Mockito.when().doAnswer() to mimic the asynchronous behavior of the GWT server calls.

Summary

With GwtMockitoTestRunner using byte code manipulation final/static/native methods will no longer get in the way of using Mockito. It also quickly turns GWT.create() into creating Mockito objects. Now by using Mockito’s doAnswer() and thenAnswer() techniques, you can test the business logic of your GWT components w/out the need of the expense of GWTTestCase or PockerMockito.

Nothing says you have to stick to using just one JUnit test runner for your unit tests. We currently use 4 test runners, and in order of preference: default JUnit test runner, Mockito test runner, GwtMockito test runner, and PowerMockito test runner. Our test coverage and developer happiness improved once we started using GwtMockito.

Feel free to check out my github repository of this sample application at gwtMockitoExample. Intellij IDEA 12.1 files are also provided. It is configured for a 64bit Java 1.7 SDK, and GWT 2.5.1, but could easily be changed to other versions, as necessary.

About the Author

Object Partners profile.

One thought on “Testing GWT with GwtMockito

  1. Jose Ribeiro says:

    Great post! It’s really helpful!

    But, how about GWT + GXT3 testing.

    Cheers
    Zekitow

  2. Neil Buesing says:

    Zekitow,

    GXT3 does make things more difficult, especially with some of the classes where it doesn’t use GWT.create(), but calls new directly. However, with GwtMockito 1.1.x they intoduced getClassesToStub() and you can add byte-code manipulation (removing final & native modifiers, and returning default value) to GXT classes as well as your own.

    If you do something like the following, then you can can test more with GXT. Mileage may very, depending on the GXT components you are using, but extending the GxtMockitoTestRunner and adding ot the getClassesToStub() is the way to go. Just be sure you are looking at the API/documentation for GwtMockito 1.1.x, not 1.0.

    @RunWith(MyTest.TestRunner.class)
    public class MyTest {

    public static class TestRunner extends GwtMockitoTestRunner {

    public TestRunner(Class unitTestClass) throws InitializationError {
    super(unitTestClass);
    }

    @Override
    protected Collection<Class> getClassesToStub() {
    Collection<Class> classes = super.getClassesToStub();
    classes.add(CommonStyles.class);
    classes.add(Component.class);
    classes.add(Container.class);
    classes.add(AbstractHtmlLayoutContainer.class);
    classes.add(HtmlLayoutContainer.class);
    return classes;
    }
    }

    }

    1. zekitow says:

      Very nice! I’ll try to use it! Thanks again! 🙂

  3. Santlal says:

    How do you find code coverage of your testcase ?

    1. Rukmani says:

      You can make use of Eclemma a plugin to find out the code coverage.

Leave a Reply

Your email address will not be published.

Related Blog Posts
Natively Compiled Java on Google App Engine
Google App Engine is a platform-as-a-service product that is marketed as a way to get your applications into the cloud without necessarily knowing all of the infrastructure bits and pieces to do so. Google App […]
Building Better Data Visualization Experiences: Part 2 of 2
If you don't have a Ph.D. in data science, the raw data might be difficult to comprehend. This is where data visualization comes in.
Unleashing Feature Flags onto Kafka Consumers
Feature flags are a tool to strategically enable or disable functionality at runtime. They are often used to drive different user experiences but can also be useful in real-time data systems. In this post, we’ll […]
A security model for developers
Software security is more important than ever, but developing secure applications is more confusing than ever. TLS, mTLS, RBAC, SAML, OAUTH, OWASP, GDPR, SASL, RSA, JWT, cookie, attack vector, DDoS, firewall, VPN, security groups, exploit, […]