Archive for the ‘g&g unit testing’ Category

Unit testing grails tag libs

August 16, 2009

Suppose you want to write your own tag library in grails. You put the tag lib class in grails-app/taglib. You put the test for the tag lib in test/unit. But how do you write the unit test?

You let your test class extend TagLibUnitTestCase. But that doesn’t solve all problems. We wrote a tag lib for internationalising error messages. And we ran into two problems:

  1. The tag lib writes to an output stream. We want to intercept what is written to the output stream. But how do we create a mock for the output stream?
  2. Our tag lib reads messages from a message source. Within the tag lib class, the message source is retrieved from a grailsAttributes property. It seems we have to replace this property by a mock. But how?

Intercepting the output

The answer to the first question isn’t all that difficult. The tag lib has a property out that contains the output stream. We can simply replace it, by using meta object programming. We set up the cut (class under test) in our setUp() method. Do not forget the call to super.setUp(), because otherwise your test won’t work.

class I18nErrorsTagLibUnitTests extends TagLibUnitTestCase {

  private I18nErrorsTagLib cut
  private StringWriter output

  protected void setUp() {
    super.setUp()
    cut = new I18nErrorsTagLib()
    output = new StringWriter()
    cut.metaClass.out = output
  }
}

We can now simply test if the correct output is written, by making assertions on the contents of the output object:

  void testSimpleMessage() {
    ...
    // call a method on the tag lib
    cut.message(error: errorObject)
    // check the output
    assertEquals "<output written by tag lib>", output.toString()
  }

Injecting the message source

Replacing the object’s message source by our mock object follows the same principle. But there are a few more steps involved. To get the message source, the tag lib does the following:

  1. The tag lib gets the value from its grailsAttributes property.
  2. The grailsAttributes object has a function getApplicationContext().
  3. On the application context, the bean with name “messageSource” is retrieved.

In other words, the tag lib uses the following code to get the message source:

  def messageSource = grailsAttributes.getApplicationContext().getBean("messageSource")

How do we mock this?

  1. First, we mock the grailsAttributes property, by overriding the metaClass’ getGrailsAttributes() method. (Remember that accessing the property grailsAttributes is the same as calling the method getGrailsAttributes()).
      cut.metaClass.getGrailsAttributes = { getGrailsAttributesStub() }
  2. Now, we build the stub for the grailAttributes object. The stub contains an application context. On the application context, the getBean(beanName) function is called to retrieve the message source. The application context is retrieved from the grailsAttributes stub, by calling getApplicationContext() on the grailsAttributes stub. We have to build quite an object. That’s why we implemented a special method getGrailsAttributesStub() that does all the building:
      private getGrailsAttributesStub() {
        def applicationContextStubber = new StubFor(ApplicationContext)
        applicationContextStubber.demand.getBean() {beanName -> getBean(beanName) }
        def grailsAttributesStubber = new StubFor(Object)
        grailsAttributesStubber.demand.getApplicationContext() {
          applicationContextStubber.proxyInstance()
        }
        grailsAttributesStubber.proxyInstance()
      }
  3. getBean(beanName) is called to retrieve the actual messageSource bean. In our test, we only expect a messageSource bean to be retrieved, and nothing else. This yields the code:
      private getBean(beanName) {
        assertEquals "messageSource", beanName
        messageSourceStubber.proxyInstance()
      }
    

messageSourceStubber is a class variable:

  private messageSourceStubber

We made this stubber a class variable, so we can define expected calls to the message source, within our tests:

    messageSourceStubber.demand.getMessage(1..1) {code, args, locale ->
      assertEquals "myclassarg.myproparg", code
      "property name from message source"
    }

That’s it. Now you know how to replace the output stream and application context of a tag lib by your own mock or stub. Happy testing!

Using Groovy’s built in unit test facilities

May 18, 2009

Automated testing increases code quality. Though your compiler may already detect some coding errors, you can detect most errors only at runtime. In a dynamic language as Groovy, even less errors are detected by your compiler, so automated testing becomes even more important.

For Java-testing I use JUnit. In Groovy, you can use some very useful Groovy classes for testing, that extend JUnit functionality with extra features. Groovy testing is based on JUnit 3. Though you can also use JUnit 4 with Groovy, it’s probably easier to use Groovy’s built in unit testing facilities.

GroovyTestCase

Let’s first have a look at Groovy’s version of the TestCase class. It is called GroovyTestCase and extends the TestCase class already provided in JUnit. Apart from the already available assert methods like assertEquals and assertTrue, it adds a number of useful assertions, like assertArrayEquals, assertLength and assertContains. Also, a shouldFail method is added, for checking exceptions:

class MyTestCase extends GroovyTestCase {
    void testException() {
        def num = "12.3{"
        def val
        shouldFail(NumberFormatException) {
            val = num as Long
        }
        assert val == null
    }
}

The code that should fail is passed to the shouldFail method as a closure. Easy, eh? Also note the use of the assert keyword instead of the assertTrue method in line 8. This is not uncommon in Groovy. Apart from running the test from a test suite, you can even run the test from the command line. Just type:

groovy MyTestCase

Since MyTestCase extends GroovyTestCase, groovy will know what to do.

Note: JUnit 3 requires a test method to be called testXXX() and to be of type void. Therefore, we have to explicitly define the type of the test method as void. The following code is equivalent to defining a method with return type Object (returning null), and is NOT detected as a test

def testException() {
    // wrong! return type of method is compiled to Object, making it not a test method!
}

StubFor

Very often, classes cooperate. Of course you could write code for testing a number of classes at the same time. Integration testing can be an important part of your test strategy. However, before you do integration tests, you should unit test your classes in isolation. If your class under test depends on other classes, those other classes should be stubbed or mocked. Stubs or mocks provide predefined, fake functionality that is used specifically in your test.

The following code defines a stub:

import groovy.mock.interceptor.*

class Collaborator {}

def stubber = new StubFor(Collaborator.class)
stubber.demand.one()  { "calling one" }
stubber.demand.two()  { arg -> "two(${arg}), first time" }
stubber.demand.two()  { arg -> "two(${arg}), second time" }
stubber.use {
    def stub = new Collaborator()
    assert "two(hi), first time" == stub.two("hi")
    assert "two(there), second time" == stub.two("there")
}

Within the use clause, each instantiation of the stubbed class returns a stub for the class, instead of a real class. Not that, although we defined a “one” method for the stub, we never called it.

MockFor

A stub provides functionality for your test, but does not check if it is called correctly. In the above example, we might want to check that the test actually calls the defined methods, and calls them in the right order. In that case, we use a mock instead of a stub. We can easily demonstrate this by replacing StubFor in line 5 of the above example by MockFor, and run the example.

Exception thrown: No call to 'two' expected at this point. Still 1 call(s) to 'one' expected.

Groovy now checks that you call the one method first, before you are calling the two method twice. You can also specify that a
function must be called a number of times:

stubber.demand.one(1..3)  { "calling one" }

The function must now be called one to three times, returning “calling one” each time. If you do not call it the required number of times, you’ll get an assertion error.

Explicitly proxying a stub

With the use keyword, the new Collaborator() constructor is diverted to a stub or mock constructor. You can also call the mock or stub constructor explicitly, without a use keyword. If you do so, for a mock you must explicitly verify the method calls, by calling the verify() method. For a stub, you can call the verify() method. The difference between mocks and stubs, is that for mocks, both the number of method calls and the order of the method calls is verified. This is the same behaviour as when you use the use keyword. For stubs, only the number of method calls will be verified. This is not the same behaviour as when you use the use keyword. If you use the use keyword on a stub, by default the verify method is not called.

In the next example, we explicitly call the stub constructor. At the end, we add a call to the verify method, so that the number of method calls is checked. This condition won’t be checked when using the use keyword. The example will run perfectly, even if the order of the method calls differs. The number of method calls is correct, and that is what is verified.

def stubber = new StubFor(Collaborator.class)
stubber.demand.one()  { "calling one" }
stubber.demand.two()  {  "calling two" }
def stub = new stubber.proxyInstance()
assert "calling two" == stub.two()
assert "calling one" == stub.one()
stubber.verify(stub)