Music, software, life… and stuff.
[ Twitter ] [ GitHub ] [ Linked In ]
Recently there was a query on the grails-user mailing list asking how to create a separate test suite (in the poster’s terminology). In Grails’ terminology, what the poster wanted was a separate test type that could be run separately.
The following is an expansion on the solution offered in the thread.
There are two core concepts in the test system; types and phases.
A test phase refers to the state of the application at test time. Grails comes with 4…
Unit - no application state, only the classpath is configuredIntegration - application running (e.g. database, beans), but not listening for http requestsFunctional - application is fully runningOther - same as UnitHere’s how to create your own test phase.
In your scripts/_Events.groovy file…
// 1. add the name of your phase to this variable with this event handler
eventAllTestsStart = {
phasesToRun << "custom"
}
// 2. Create a «phase name»Tests variable containing a list of test types (more on this later)
customTests = ["custom"]
// 3. Create pre and post closures
customTestPhasePreparation = {
// called at the start of the phase
}
customTestPhaseCleanUp = {
// called at the end of the phase
}
Even if you don’t have anything to do in your Preparation and CleanUp closures, you still need to create empty ones.
Note that the name of a test phase has no real correlation to it’s type’s names. In this example we just happen to have a type with name custom in a phase named custom.
If you need your phase to be like one of the standard phases, just call that phase’s handlers…
customTestPhasePreparation = {
integrationTestPhasePreparation()
}
customTestPhaseCleanUp = {
integrationTestPhaseCleanUp()
}
That’s all there is to it.
A test type is really two things; a grouping of tests and a test running mechanism.
Above we had…
… // 2. Create a «phase name»Tests variable containing a list of test types (more on this later) customTests = ["custom"] …
The «phaseName»Tests lists contains a phase’s test types. These must either be String’s or instance of GrailsTestType. Writing a GrailsTestType implementation will be the subject of a future article (if you are interested, start with the JavaDoc on GrailsTestType and then look at implementations in the wild like the one from the Spock plugin).
Grails ships with the JUnit4GrailsTestType which is what Strings get implicitly converted to (this happens here) for both convenience and legacy reasons.
Test types are associated to a certain directory (under test) and one or more class name suffixes. The JUnit test type uses the suffix Tests pre Grails 1.3 and Tests and Test in Grails 1.3. The directory for String test types is the value (i.e. test/custom for our above example).
You don’t need to write pre/post handlers for types like you do with phases. But should you need to, here is how you do it…
eventTestSuiteStart = { typeName ->
if (typeName == 'custom') {
// do stuff
}
}
eventTestSuiteEnd = { typeName ->
if (typeName == 'custom') {
// do stuff
}
}
The event has that name due to legacy reasons.
Above we created an integration-like phase called custom. Without a bit of extra work, our tests won’t be completely like standard integration tests in that they won’t have transaction rollback and other bits and pieces. To do this you need to register a JUnit4GrailsTestType so it can be configured. Here is a complete example on how you would do this…
import org.codehaus.groovy.grails.test.junit4.JUnit4GrailsTestType
// 1. add the name of your phase to this variable with this event handler
eventAllTestsStart = {
phasesToRun << "custom"
}
// 2. Create a custom test type
def testTypeName = "custom"
def testDirectory = "custom"
def testMode = new GrailsTestMode(autowire: true, wrapInTransaction: true, wrapInRequestEnvironment: true)
def customTestType = new JUnit4GrailsTestType(testTypeName, testDirectory, testMode)
// 3. Create a «phase name»Tests variable containing the test type(s)
customTests = [customTestType]
// 4. Create pre and post closures
customTestPhasePreparation = {
integrationTestPhasePreparation()
}
customTestPhaseCleanUp = {
integrationTestPhaseCleanUp()
}
For a functional-like phase you would do…
import org.codehaus.groovy.grails.test.junit4.JUnit4GrailsTestType
// 1. add the name of your phase to this variable with this event handler
eventAllTestsStart = {
phasesToRun << "custom"
}
// 2. Create a custom test type
def testTypeName = "custom"
def testDirectory = "custom"
def testMode = new GrailsTestMode(autowire: true)
def customTestType = new JUnit4GrailsTestType(testTypeName, testDirectory, testMode)
// 3. Create a «phase name»Tests variable containing the test type(s)
customTests = [customTestType]
// 4. Create pre and post closures
customTestPhasePreparation = {
functionalTestPhasePreparation()
}
customTestPhaseCleanUp = {
functionalTestPhaseCleanUp()
}
(functional tests don’t need rollback transactions or fake request environments)
For completeness, here’s a unit-like phase (though you could just use a String)…
import org.codehaus.groovy.grails.test.junit4.JUnit4GrailsTestType
// 1. add the name of your phase to this variable with this event handler
eventAllTestsStart = {
phasesToRun << "custom"
}
// 2. Create a custom test type
def testTypeName = "custom"
def testDirectory = "custom"
def customTestType = new JUnit4GrailsTestType(testTypeName, testDirectory)
// 3. Create a «phase name»Tests variable containing the test type(s)
customTests = [customTestType]
// 4. Create pre and post closures
customTestPhasePreparation = {
unitTestPhasePreparation()
}
customTestPhaseCleanUp = {
unitTestPhaseCleanUp()
}
Once registered and configured, your custom tests can be run just like any other tests using grails test-app. You can even target them like normal…
grails test-app custom: // run all types in the custom phase
grails test-app :custom // run the custom type in all phases
grails test-app custom:custom // run the custom type in the custom phase
You can even target tests and test methods
grails test-app custom:custom Person* Product.testSave
The above example would run all test classes starting with Person (and ending in Test or Tests) and the testSave test in ProductTest or ProductTests.
The Grails manual has a section on running tests.
The original email query was asking for a solution for having a test type that didn’t run with grails test-app, but ran when explicitly requested. Given the above, the following should make sense…
eventAllTestsStart = {
if (testOptions.customOnly) {
phasesToRun = ["integration"] // remove the other phases
integrationTests = [] // remove the normal integration tests
addCustomTestType()
} else if (testOptions.withCustom) {
addCustomTestType()
}
}
addCustomTestType = {
integrationTests << "ipbx"
}
(The testOptions map contains all switch or parameter style arguments passed to grails test-app)
So this gives us…
grails test-app // don't run the custom type
grails test-app -only-custom // run ONLY the custom type
grails test-app -with-custom // run ALL types including our custom type
Laziness on my part. This article will likely be the basis of what will end up in the manual (GRAILS-6301).
Posted: May 20th, 2010 @ 9:21 pm
Tags: #software #grails #testing
The recently released grails-webtest 2.0.2 now installs WebTest via dependency resolution.
This allows you to work around the HTMLUnit 2.4 incompatibility with JQuery. WebTest 3.0 depends on HTMLUnit 2.4, but we can force the use of HTMLUnit 2.5 which works with JQuery.
Simply add it as a dependency in your app.
grails.project.dependency.resolution = {
inherits "global"
log "warn"
repositories {
grailsHome()
mavenCentral()
}
dependencies {
test('net.sourceforge.htmlunit:htmlunit:2.5') {
excludes 'xalan' // IVY-1006 - use xalan 2.7.0 to avoid (see below)
excludes 'xml-apis' // GROOVY-3356
}
test('xalan:xalan:2.7.0') {
excludes 'xml-apis' // GROOVY-3356
}
}
}
Posted: Mar 11th, 2010 @ 3:16 pm
Update: I have released a plugin that makes working with scoped proxies a little bit easier.
Grails has supported “scoping” services for as long as I have been working with it. Surprisingly, you very rarely here of people using this feature. For my money, it’s one of the lowest cost techniques available to avoid the inherent spaghetti in referencing the session and request (for all intents and purposes) global objects.
This feature is built on top of Spring’s bean scoping. However, you don’t need to know much Spring to get value out of this in Grails.
Scoping a service is as simple as declaring a static scope property with the name of the desired scope…
class MyScopedService {
static scope = 'session'
}
So now, for each distinct session there will be a distinct instance of MyScopedService in our application.
An easy to understand use case for this might be a shopping cart…
class CartService {
static scope = 'session'
void addCartItem(cartItem) {
// …
}
def getPrice() {
// …
}
}
We would use this in our controller like so…
class CartController {
def cartService
def addItem = {
cartService.addItem(/* cart item */)
}
def price = {
println "Cart price is: " + cartService.price
}
}
You might be wondering just which session that cartService belongs to. Grails controllers are prototype scoped beans (which means a new one is created whenever it is retrieved from the application context) and only ever created inside of a request environment. Therefore, a Grails controller always lives within the context of a session. So when the controller instance is created by Grails at the start of the request, it can be injected with the instance of cartService that correlates to the session that the request is for.
But what about objects that don’t live inside a request (like taglibs)? For that we need a scoped proxy.
So we want to have a taglib that renders the current price of the shopping cart. We could pass the cartService instance to the view layer via our controller action and then pass it to the taglib, but that gets tiresome real quick when you start doing it for lots of actions. Since our cart is now a Spring managed bean we could try adding it as a dependency of our taglib…
class CartTagLib {
def cartService
def price = {
out << cartService.price
}
}
If you try and do this you are going to get…
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cartService': Scope 'session' is not active for the current thread;
Grails taglibs are singleton scoped so are created at application startup when the notion of session doesn’t make any sense. What we can do though is create a singleton proxy that delegates to the relevant cartService object at execution time (taglibs are always executed during a request so there will be session when the tag is executed).
With Grails 1.2 and earlier, we have to create this proxy manually by adding this to grails-app/conf/resources.groovy…
import org.springframework.aop.scope.ScopedProxyFactoryBean
beans = {
cartServiceProxy(ScopedProxyFactoryBean) {
targetBeanName = 'cartService'
proxyTargetClass = true
}
}
This, in effect, creates a singleton bean, which is a dynamically generated subclass of CartService, that delegates method/property calls to the cartService instance stored in the session. Check out Spring’s docs on scope proxies if you want more information on this.
Now we just rewrite our taglib to use our proxy…
class CartTagLib {
def cartServiceProxy
def price = {
out << cartServiceProxy.price
}
}
You can now use your cartServiceProxy anywhere like other services or filters. As long as the code that calls cartServiceProxy is executed in a request environment everything will work as expected in a completely thread safe manner.
Grails 1.3 will make scoped beans even more attractive by removing the need to define your own proxies. All you will have to do is…
class CartService {
static scope = 'session'
static proxy = true
}
To have a proxy named cartServiceProxy created for you. You can track this new feature via the Grails issue tracker.
Grails 1.3 will also support scoped tag libs in the same manner as services.
When integration testing scoped services, you need to be aware of the request/session lifecycle semantics.
Each test method is run in it’s own unique environment. This means two things; you must use a proxy to access a request or session scoped in a test, and each test method will have it’s own distinct underlying service instance.
class SomeTests extends GroovyTestCase {
import grails.plugin.spock.*
class ScopedServiceSpec extends IntegrationSpec {
def sessionScopedServiceProxy
def requestScopedServiceProxy
void test1() {
expect:
sessionScopedServiceProxy.property == null
requestScopedServiceProxy.property == null
when:
sessionScopedServiceProxy.property = 1
requestScopedServiceProxy.property = 1
then:
sessionScopedServiceProxy.property == 1
requestScopedServiceProxy.property == 1
}
void test2() {
expect:
sessionScopedServiceProxy.property == null
requestScopedServiceProxy.property == null
when:
sessionScopedServiceProxy.property = 2
requestScopedServiceProxy.property = 2
then:
sessionScopedServiceProxy.property == 2
requestScopedServiceProxy.property == 2
}
}
For me it’s really about expressing intent. Some aspects of your application, like a shopping cart, are so pervasive that they end up everywhere in your code. It’s very hard to track down who is getting something from or setting something in the session or request objects in controllers, taglibs or filters. If you use scoped services, it’s very easy to see who is doing what. I can tell a controller does something with the cart because I see def cartService at the start of the class. That’s easier to spot than session.cart buried in an action. I also find it allows me to stay more focussed in the language of my problem domain.
Scoped services are a great tool to have in your arsenal. In an upcoming post, I’ll be discussing using custom scopes or lifecycles for your scoped services.
Posted: Mar 9th, 2010 @ 9:46 pm
I released a new version of the Grails JMS plugin (0.5) over the weekend. This release features completely rewritten internals to expose every configuration aspect of the underlying Spring JMS classes. JMS is a complicated topic with lots of setup and configuration options so this level of access is necessary.
What’s novel about the approach is that it allows users to configure the underlying beans via the Grails application config, rather than via direct Spring bean configuration. This has the advantage of being more generally accessible as a lot of Grails developers still shy away from directly configuring beans. It also has the advantage of allowing the plugin to assert a certain level of control over the bean definitions.
The plugin makes it convenient to specify service methods as JMS listeners.
import grails.plugin.jms.Subscriber
class ListeningService {
@Subscriber
void interestingStuff(payload) {
}
}
Whenever a message is sent to the topic “interestingStuff”, the message will be delivered to this service method.
There are two aspects to receiving JMS messages with Spring’s JMS support; containers and adapters. For each listener there is a distinct container and adapter pair. In a plain Spring app, you would configure a pair of these beans to receive your messages. If you have a look at those classes, there are a lot of config options. The goal of this plugin release was to give you access to those options should you need it, but not force you to define everything yourself.
The @Subscriber annotation has container and adapter parameters that default to "standard". These parameters are the names of the abstract beans that the concrete listener and adapter instances shall inherit from. There are implicit suffixes though; a container value of "standard" actually means the bean standardJmsListenerContainer and so forth. The plugin does force some properties on the concrete instances, but very few. The majority of configuration is controlled by the abstract base.
The other half of the story is how the beans are defined based on the config. This is driven by the MapBasedBeanDefinitionBuilder that takes a name and Map of properties a certain format and registers a bean based on the map data. There are also certain MapBasedBeanDefinitionBuilder subclasses in the plugin like JmsListenerContainerAbstractBeanDefinitionBuilder that specialise in creating certain types of beans.
The default set of beans configurations look like this…
import org.springframework.jms.support.converter.SimpleMessageConverter
import org.springframework.jms.listener.DefaultMessageListenerContainer
templates {
standard {
connectionFactoryBean = "jmsConnectionFactory"
messageConverter = new SimpleMessageConverter()
}
}
containers {
standard {
concurrentConsumers = 1
subscriptionDurable = false
autoStartup = false
connectionFactoryBean = "jmsConnectionFactory"
messageSelector = null
cacheLevel = DefaultMessageListenerContainer.CACHE_SESSION
}
}
adapters {
standard {
messageConverter = new SimpleMessageConverter()
persistenceInterceptorBean = 'persistenceInterceptor'
}
}
The details aren’t important. The point is to illustrate the syntax.
This default config gets merged with the application config under the jms key (e.g. grailsApplication.config.jms). So to override the standard container to use a different connection factory we would have the following in our Config.groovy
jms {
containers {
standard {
connectionFactoryBean = "someOtherJmsConnectionFactory"
}
}
}
Because Config.groovy is environment aware, we can also do things like
environments {
development {
jms.containers.standard.connectionFactoryBean = "someOtherJmsConnectionFactory"
}
test {
jms.containers.standard.connectionFactoryBean = "testJmsConnectionFactory"
}
}
You could even change the class of the default container definition.
jms {
containers {
standard {
meta {
clazz = SomeOtherListenerContainer
}
}
}
}
This mechanism also supports having more than one container type
jms {
containers {
other {
meta {
parentBean = "standardJmsListenerContainer"
}
connectionFactoryBean = "otherJmsConnectionFactory"
}
}
}
This creates a new container type called other that inherits all of the configuration from the standard container, but overrides the connection factory.
You would then use this container by specifying the container on the listener.
import grails.plugin.jms.Subscriber
class ListeningService {
@Subscriber(container = "other")
void interestingStuff(payload) {
}
}
The point of this article is not specifically to talk about the JMS plugin. This approach to bean configuration seems to work quite well when users need access to the underlying beans in an optional manner. This may be an approach that other plugin authors might want to adopt.
Posted: Mar 9th, 2010 @ 10:42 am
I am currently working on a set of JSON over HTTP web services APIs between Grails applications. Producing JSON content in Grails applications is ridiculously trivial, but the story on consuming content is not so clear.
I am using Tom Nichol’s HTTPBuilder for consumption. It’s a great library, but does take a little getting used to. Fortunately, the documentation is excellent.
HTTPBuilder ships with JSON support based on Andres Almiray’s json-lib. That works fine, but I was worried about a potential impedance mismatch between json-lib’s encoding/decoding and Grails’.
Here’s how I configured HTTPBuilder to use Grails’ JSON bits for encoding/decoding JSON data…
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.ParserRegistry
import groovyx.net.http.ContentType.JSON
import org.apache.http.entity.EntityTemplate
import org.apache.http.entity.ContentProducer
import org.apache.http.message.BasicHeader
// create a builder instance
def builder = new HTTPBuilder()
// the closure that takes a HttpServletResponse and returns an object
def jsonParser = { response ->
grails.converters.JSON.parse(new InputStreamReader(response.entity.content, ParserRegistry.getCharset(response)))
}
// the closure that takes an object and returns an org.apache.http.HttpEntity
def jsonEncoder = { value ->
def json = value instanceof Closure ? new grails.web.JSONBuilder().build(value) : new grails.converters.JSON(value)
def producer = [writeTo: { OutputStream out -> out.withWriter { json.render(it) } }] as ContentProducer
def entity = new EntityTemplate(producer)
entity.contentType = new BasicHeader("Content-Type", JSON.toString())
entity
}
// for each JSON content type, install the handler
JSON.contentTypeStrings.each {
builder.parser."$it" = jsonParser
builder.encoder."$it" = jsonEncoder
}
Note that you have to configure each created HTTPBuilder instance.
Here is some contrived example usage. We are calling a JSON “mirror” service that simply just returns the JSON it was sent.
import grails.plugin.spock.*
import groovyx.net.http.Method.POST
import groovyx.net.http.ContentType.JSON
class HttpBuilderWithGrailsJsonSpec extends UnitSpec {
void "test it all works like it should"() {
given: "a configured HTTP builder"
def builder = new HTTPBuilder("http://jsonmirror.org")
// configure the builder as per above
when: "I post '{a: 1}' to the JSON mirror service"
def requestMethod = POST
def responseContentType = JSON
def result = builder.request(requestMethod, responseContentType) {
def requestContentType = JSON
send(requestContentType) {
a = 1
}
}
then: "I get the JSON '{a: 1}' returned"
result.a == 1
}
}
Posted: Feb 25th, 2010 @ 1:01 pm