At our company’s blog, we have already considered many types of Grails testing. But there is yet one testing type, on which we have to take a look. In this article, we will check out the overview of writing functional tests using Geb/Spock technologies.
Geb and Spock are young and fast-developing technologies. Spock provides fast and convenient test writing. And Geb provides testing of the web application using HTMLUnit and the real browsers’ web drivers. Let’s look at how it works. At first, let’s install Geb and Spock plugins.
grails install-plugin geb
grails install-plugin spockThen you should specify the following code in your BuildConfig.groovy dependencies
dependencies {
test("org.seleniumhq.selenium:selenium-htmlunit-driver:2.0rc3") {
exclude "xml-apis"
}
test("org.seleniumhq.selenium:selenium-chrome-driver:2.0rc3")
test("org.seleniumhq.selenium:selenium-firefox-driver:2.0rc3")
test "org.codehaus.geb:geb-spock:0.6.0"
}At the test running stage, you may experience some troubles because of a conflict between this plugin and some others you have already installed in your project; one of these conflicts is related to the “release” plugin usage. For me, adding the following lines to the build config worked.
dependencies {
//code we’ve already specified
build('net.sourceforge.nekohtml:nekohtml:1.9.14') {
excludes "xml-apis"
}
}
plugins {
build(':release:1.0.0.M3') {
excludes "svn", 'nekohtml'
}
}Now, when we have everything ready, let’s get down to business. Unfortunately, as you may already notice, Grails has nothing like Grails create-functional-test, so you should create functional tests by yourself, specifying them in the directory test/functional, or use this solution https://adhockery.blogspot.com/2010/08/auto-generate-spock-specs-for-grails.html.
The next step would be creating page objects that you are going to use in your tests. Let’s write a simple test that is gonna test the login page generated by Spring Security. The login page HTML looks as follows:
<form action='${postUrl}' method='POST' id="loginForm" name="loginForm">
<p class="form_label"><g:message code='ex.ui.login.auth.username' default="Username"/></p>
<p><span class="login">
<input type="text" name="j_username" id="username" size="15"/>
</span></p>
<p class="form_label"><g:message code='ex.ui.login.auth.password' default="Password"/></p>
<p><span class="login">
<input type="password" name="j_password" id="password" size="15"/>
</span></p>
<input type="checkbox" class="checkbox" name="${rememberMeParameter}" id="remember_me" checked="checked"/>
<label for="remember_me"><g:message code='ex.ui.login.auth.remember' default="Remember me"/></label>
<g:submitButton name="loginBtn" value="${message(code:'ex.ui.login.auth.loginBtn')}"/>
</form> We’re gonna use the login page and the home page for our test. Their objects should look like this:
package com.sysgears.example.pages
import geb.Page
class ViewUserPage extends Page {
static url = "admin/view"
static at = { title == "Users" }
static content = {
}
}package com.sysgears.example.pages
import geb.Page
class LoginPage extends Page {
static url = "login/auth"
static at = { title == "Login" }
static content = {
loginForm { $("form") }
loginButton { $("input", value: "Login") }
}
}Let’s take a closer look at the properties: “at” closure specifies a condition when this is a current page. Values at the “content” property help us to access the page elements in the tests. Notice that access to the elements is provided in jQuery-like language, which makes accessing the elements extremely convenient. Now, let’s check out the test example.
package com.sysgears.example;
import geb.spock.GebReportingSpec;
import spock.lang.Stepwise;
import com.sysgears.example.pages.*
@Stepwise
class LoginAuthSpec extends GebReportingSpec {
String getBaseUrl() { "https://localhost:8080/" }
File getReportDir() { new File("target/reports/geb") }
def "invalid login"() {
given: "I am at the login page"
to LoginPage
when: "I am entering invalid password"
loginForm.j_username = "admin"
loginForm.j_password = "ioguffwf"
loginButton.click()
then: "I am being redirected to the login page, the password I entered is wrong"
at LoginPage
loginForm.j_username == "admin"
!loginForm.j_password
}
def "admin login"() {
given : "I am at the login page"
to LoginPage
when: "I am entering valid username and password"
loginForm.j_username = "admin"
loginForm.j_password = "1234"
loginButton.click()
then: "I am being redirected to the admin homepage"
at ViewUserPage
$().text().contains("You are logged in as admin")
}
}Let’s take a closer look. Test methods here broke on the sections given, when, and then. ‘Given’ gives initial conditions for the test, ‘when’ specifies test behavior, and ‘then’ checks assertions at the end of the test. Test methods: to() method sends an HTTP request to the URL, which was specified in the url property of the page object; at() method checks whether the specified page is current or not, for doing this, the condition specified in the “at” property is being used. Notice that you may access HTML elements not only via those values, which were defined in the content property, but also access them directly from the test.
For more examples, please see these examples from the Geb
https://github.com/geb/geb-example-grails .
Also, the Geb book should be very useful
https://groovy.apache.org/geb/manual/current/
