EasyB + Grails Testing
Dependency :
compile ":easyb:2.0.5"
Summary
Description
Overview
Groovy testing implementation of easyb - exposes all of the easyb functionality and an infrastructure to expose the testing functionality that is normally available only to Grails' Unit Testing framework.The current released version of the Grails easyb plugin works only with versions 1.2 and above of Grails. This is because the Grails testing infrastructure changed significantly between 1.1 and 1.2.See http://www.easyb.org for how to use EasyB.You may also be interested in the easyb acceptance test plugin.Installation
As with any Grails plug-in, the user can run the install plug-in command to install a plug-in:grails install-plugin easyb
Where do my files go?
As with other Grails testing frameworks, tests go in your test/unit, test/integration and test/functional sub directories in the test directory. For example, if doing JAX-RS easyb testing, you can put a file called CartResource.story in test/unit and easyb will run that when it is running unit tests.Both HTML & plain text reports are now stored in the "target/test-reports/" directory inside the grails project.Running EasyB
After installing, users can use the following commands to run unit, integration, functional or easyb stories.- Run all EasyB & Grails tests including stories, unit & integration "grails test-app"
- Run all easyb stories "grails test-app :easyb"
- Run unit test stories for easyb: "grails test-app unit:easyb"
- Run integration test stories for easyb: "grails test-app integration:easyb"
- Run single unit test story: "grails test-app ExampleService unit:easyb"
It is recommended that you suffix your stories and specifications with .story and .specification to make it more clear for others and Grails easyb when trying to run your tests. Ending in one of these suffixes will ensure you easyb tests don't clash with other test plugins.
Best Practice
It is best practice to put your tests (.story or .specification) in the same packages as the classes being tested. The grails easyb plugin will automatically match the tests with their corresponding class. For example:- com.bluetrainsoftware.AuthorController.story will correspond to com.bluetrainsoftware.AuthorController.groovy
- com.bluetrainsoftware.AuthorTagLib.story will correspond to com.bluetrainsoftware.AuthorTagLib.story
grailsTest "controller", "NameOfControllerClass"
Using Services
There is a keyword that can be used in Specifications and Stories in the integration scope called "inject"./** * introduced by Jeffrey C. Erikson */scenario "we should be able to inject services", { when "requesting the author service bean", { inject "authorService" } then "author service should be callable", { authorService.doSomething(3).shouldBe "burp" } }scenario "non existent beans should fail", { when "we have a request for a non-existent bean", { beanReq = { inject "wibble" } } then "it should fail", { ensureThrows(Exception) { beanReq.call() } } }
Controller Unit Tests
Since the EasyB plug-in leverages the Grail testing framework, writing controller unit stories work very similar to writing standard controller unit tests. Take the following controller:class SearchController {
def ldapService def index = {
def result = [:]
if (!params.query?.trim()) {
return result
} try {
if(params.user) {
result.searchResult = User.findByLastname(params.query, params)
} else {
result.searchResult = ldapService.search(params.query, params)
} } catch (Throwable t) {
log.error("Error while performing search", t)
result.searchResult = null
result.exception = true
}
return result
}
}- No search parameter "query" is passed and the method returns an empty result
- Search parameter is passed and search is performed
- Search parameter is passed, the "user" search parameter is passed indicating a user only search, and search is performed
- Search parameter is passed, exception is thrown while performing a search, an empty result is returned
scenario "Search controller returns results of a ldap search", { given "Controller is instantiated", { mockController SearchController controller = new SearchController() ldapService = mockFor(LdapService) ldapService.metaClass.search = { String param, Map params -> def searchResult = [:] searchResult.total = 2 searchResult.max = 10 searchResult.offset = 0 searchResult.results = [new User(name: "Test 1"), new User(name: "Test 2")] return searchResult } controller.ldapService = ldapService } when "controller receives request for index action" and "a search parameter is included", { controller.params.query = "Smith" result = controller.index() } then "controller display search page", { controller.redirectArgs.view.shouldBe null } and "controller returns a list of search results", { result.searchResult.total.shouldBe 2 result.searchResult.max.shouldBe 10 result.searchResult.results.size().shouldBe 2 } }scenario "Search controller responds to a User search", { given "Controller is instantiated", { mockController SearchController User.metaClass.static.findByLastname = { String param, Map params -> def searchResult = [:] searchResult.total = 2 searchResult.max = 10 searchResult.offset = 0 searchResult.results = [new User(name: "Test 1"), new User(name: "Test2")] return searchResult } controller = new SearchController() } when "controller receives request for index action" and "a search parameter ‘Smith’ is included", { controller.params.query = "Smith" } and "user search parameter is included", { controller.params.user = "t" result = controller.index() } then "controller displays search page", { controller.redirectArgs.view.shouldBe null } and "controller returns a list of search results", { result.searchResult.total.shouldBe 2 result.searchResult.max.shouldBe 10 result.searchResult.results.size().shouldBe 2 } }scenario "Search controller responds to index request without search parameter", { given "Controller is instantiated", { mockController SearchController controller = new SearchController() } when "controller receives request for index action" and "no search parameter is passed", { result = controller.index() } then "controller displays search page", { controller.redirectArgs.view.shouldBe null } and "controller should return null search results", { result.searchResult.shouldBe null } }scenario "Search controller handles exception when performing search", { given "Controller is instantiated", { mockController SearchController controller = new SearchController() ldapService = mockFor(LdapService) ldapService.metaClass.search = { String param, Map params -> throw new Exception("Search Exception") } controller.ldapService = ldapService } when "controller receives request for index action" and "search parameter 'Smith' is passed", { controller.params.query = "Smith" result = controller.index() } then "controller indicates exception was thrown", { result.exception.shouldBe true } and "controller should return null search results", { result.searchResult.shouldBe null } }