Get ahead
VMware offers training and certification to turbo-charge your progress.
Learn moreIn my third post I discussed how to use WebDriver to make designing our tests easier with the Page Object Pattern. In this post, I'm going to discuss how to use Geb to make our testing with MockMvc
more Groovy.
Geb is backed by WebDriver, so it offers many of the same benefits we got from WebDriver. However, Geb makes things even easier by taking care of some of the boiler plate code for us. Of course we want to use MockMvc so that we do no need to deploy our code to a server. The easiest way to understand the benefits of using Geb is to jump into an example.
NOTE: Another great feature of Geb is its exceptional documentation.
Before you use the project, you must ensure to update your dependencies. Instructions for both Maven and Gradle can be found on the site documentation.
Now that we have the correct dependencies, we can use Geb in our unit tests. The complete code sample for using Geb and Spring MVC Test can be found in GebCreateMessagesSpec.
In order to use HtmlUnit and Spring MVC Test we must first create a MockMvc
instance. There is plenty of documentation on how to create a MockMvc
instance, but we will review how to create a MockMvc
instance very quickly in this section.
The first step is to create a new GebReportingSpec
class that is annotated as shown below:
@ContextConfiguration(classes=[WebMvcConfig,MockDataConfig])
@WebAppConfiguration
class GebCreateMessagesSpec extends GebReportingSpec {
@Autowired
WebApplicationContext context;
WebDriver driver;
...
}
@Autowired
annotations will be honored.@ContextConfiguration
tells Spring what configuration to load. You will notice that we are loading a mock instance of our data tier to improve the performance of our tests. If we wanted, we could optionally run the tests against a real database. However, this has the disadvantages we mentioned previously.@WebAppConfiguration
indicates that a WebApplicationContext
should be created rather than a ApplicationContext
.Next we need to create our MockMvc
instance from the context
. An example of how to do this has been provided below:
def setup() {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build()
...
}
Of course this is just one way to create a MockMvc
instance. We could have decided to add a Servlet Filter, use a Standalone setup, etc. The important thing is that we need an instance of MockMvc
. For additional information on creating a MockMvc
instance refer to the Spring MVC Test documentation.
Now that we have created the MockMvc
instance, we need to create a MockMvcHtmlUnitDriver
which ensures we use the MockMvc
instance we created in the previous step. We then use Geb's explicit lifecycle and set the driver on Geb's Browser instance.
WebDriver driver;
def setup() {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build()
driver = new MockMvcHtmlUnitDriver(mockMvc, true)
browser.driver = driver
}
def destroy() {
if(driver != null) {
driver.close();
}
}
Now we can use Geb as we normally would, but without the need to deploy our application. For example, we can request the view to create a message with the following:
to CreateMessagePage
We can then fill out the form and submit it to create a message.
form.summary = expectedSummary
form.text = expectedMessage
submit.click(ViewMessagePage)
Any unrecognized method calls or property accesses/references that are not found will be forwarded to the current page object. This removes a lot of the boilerplate code we needed when using WebDriver directly.
Additionally, this improves on the design of our HtmlUnit test. The most obvious change is that we are now using the Page Object Pattern. As we mentioned in Why WebDriver?, we could use the Page Object Pattern with HtmlUnit, but it is much easier now.
Let's take a look at our CreateMessagePage
.
class CreateMessagePage extends Page {
static url = 'messages/form'
static at = { assert title == 'Messages : Create'; true }
static content = {
submit { $('input[type=submit]') }
form { $('form') }
errors(required:false) { $('label.error, .alert-error')?.text() }
}
}
The first thing you will notice is that our CreateMessagePage
extends the Page
. We won't go over the details of Page
, but in summary it contains base functionality for all our pages.
The next thing you will notice is that we define a URL in which this page can be found. This allows us to navigate to the page with:
to CreateMessagePage
We also have a closure that determines if we are at the specified page. It should return true if we are on the correct page. This is why we can assert that we are on the correct page with:
NOTE: We use an assertion in the closure, so we can determine where things went wrong if we were at the wrong page.
at CreateMessagePage
We last create a content closure that specifies all the areas of interest within the page. We can use a jQuery-ish Navigator API to select the content we are interested in.
Finally, we can verify that a new message was created successfully
at ViewMessagePage
success == 'Successfully created a new message'
id
date
summary == expectedSummary
message == expectedMessage
Feedback please!
If you have feedback on this blog series or the Spring Test MVC HtmlUnit, I encourage you to reach out via the comments below, github issues, or ping me on twitter @rob_winch. Of course the best feedback comes in the form of contributions.