Monthly Archives: October 2009

Testing your Grails scripts

One of the things that has longed bugged me with Grails is how difficult it is to test scripts. In the past I have pretty much resorted to manually testing the corresponding commands and hoping that nothing bad happens. As we all know, this isn’t a very reliable approach. So, I finally caved in and knocked up a system for testing Grails scripts. I even integrated it into the normal Grails test framework!

This feature is only available in the latest Grails snapshots, from build 441 onwards, so don’t bother trying this with 1.2-M3 or earlier. It will be available in 1.2-RC1 assuming that the feature isn’t pulled (an unlikely event). That’s all you need. No extra plugins or libraries are necessary. So without further ado, let’s create a new Grails script with a test.

A test-driven script

“Hello world” examples are all the rage, so who am I to buck the trend? In this instance, we’ll create a script that echoes “Hello world” to the console and also creates a file. Since I have my TDD hat on, the first step is to create a test case for the new script.

All script tests go into the test/cli directory, so create the file test/cli/HelloWorldTests.groovy and open it in an editor. The first version looks like this:

import grails.test.AbstractCliTestCase
import org.apache.commons.codec.digest.DigestUtils

/**
 * Test case for the "hello-world" Grails command.
 */
class HelloWorldTests extends AbstractCliTestCase {
    void testDefault() {
        execute([ "hello-world" ])

        assertEquals 0, waitForProcess()
        verifyHeader()

        // Make sure that the script was found.
        assertFalse "HelloWorld script not found.", output.contains("Script not found:")
    }
}

Short and sweet. First off, we extend the AbstractCliTestCase class so that we can run our target script easily and reliably, while capturing its console output. Don’t leave home without it! Or at least don’t try to write a script test without it.

The test itself, i.e. the body of the testDefault() method, demonstrates two of the most important methods provided by AbstractCliTestCase. The execute() method takes a list of command arguments, the first of which should be the name of the command you’re testing. Since our hello-world command doesn’t accept any arguments yet, we only pass the string “hello-world” to execute(). Once invoked, this method initiates a new Grails process to execute the given command.

Once the separate Grails process has started, the execute() method returns. That means your test code is back in control before the Grails command has actually done anything. What we really need to do now is wait for the Grails command to finish. Enter waitForProcess(). This behaves very simply: it will wait for the command started by execute() to finish and then return the exit code of the process. Successful completion of a command typically results in an exit code of 0, so that’s what we test for in our assert.

Now that the command has finished, we can check what the output of the command was. At this stage, we just want to check that the command was started successfully. The verifyHeader() method checks that the usual stuff printed by Grails when it starts appears in the command output. We then check that Grails didn’t print the message indicating that the command couldn’t be found. See how we check an output property? It’s provided by the abstract test case and contains the full output of the Grails command.

Running the CLI tests

So, with the test in place, let’s try running it:

grails test-app --other
This will run all tests in the “other” phase, which is the phase the CLI tests are part of. The result of this command should contain the following:

-------------------------------------------------------
Running 1 cli test...
Running test HelloWorldTests...
                    warning...FAILED
Tests Completed in 200ms ...
-------------------------------------------------------
Tests passed: 0
Tests failed: 1
-------------------------------------------------------

A quick look at the corresponding test report will show that our assertion failed: the HelloWorld script couldn’t be found. That’s easily fixed. Create a new script, scripts/HelloWorld.groovy, and put the following in it:

includeTargets << grailsScript("_GrailsSettings")

target(default: "A simple hello world script.") {
}

When you run the tests again, you will find that our test case passes now. Whoohoo! Of course, it’s still not doing anything.

Another cycle of TDD

Let’s now augment our test case by checking that the command echoes the string “Hello world” to the console and that it also creates a “dummy.txt” file in the target directory:

...
    void testDefault() {
        def targetFile = new File("target", "dummy.txt")
        targetFile.delete()

        execute([ "hello-world" ])

        assertEquals 0, waitForProcess()
        verifyHeader()

        assertFalse "HelloWorld script not found.", output.contains("Script not found:")
        assertTrue "Hello world message is missing.", output.contains("[echo] Hello world!")
        assertTrue "dummy.txt doesn't exist", targetFile.exists()
    }
...

Run the tests and you’ll find the test case is failing again, as expected. Adding the following to your new script should do the trick:

target(default: "A simple hello world script.") {
    ant.echo("Hello world!")
    new File(grailsSettings.baseDir, "target/dummy.txt").createNewFile()
}

That’s it. The command is doing what was originally required of it and now you have a test case to ensure that it doesn’t break.

User input

You should be able to extrapolate what we’ve done here to lots of scripts, but there is still one class of script that we need to handle: those that accept user input. For example, many of the “create” scripts prompt the user for a name. Others check whether the user wants to overwrite existing files. Fortunately, AbstractCliTestCase can handle this.

Let’s say we’re running the generate-views command for a given domain class and that the views already exist. The code to test this should start:

    void testGenerateViewsWithExistingViews() {
        execute([ "generate-views", "org.example.MyDomain" ])
        enterInput("n")
        enterInput("a")

        assertEquals 0, waitForProcess()
        verifyHeader()

        // Check that first view was not overwritten, but the others were.
        ...
    }

As you can see, you can have as many calls to enterInput() as you want. But remember that you should only have as many as there are requests for input from the command. Typically, the generate-views command will request input four times, once for each view. But by entering “a” the second time, the remaining views are automatically overwritten without the user being asked.

If you’re interested in a more full-featured example, my DTO Plugin has some CLI tests for its generate-dto command. Happy testing!

Introduction to the DTO plugin

Data transfer objects: you either hate them or you loathe them. They give off that kind of smell that sets the alarm bells ringing and has you reaching for the disinfectant. DRY? Sorry, not today m’am. Let’s face it, anything that has you duplicating fields and performing straight copies between objects is deeply suspicious.

Despite that, DTOs still persist (pardon the pun). When you want to serialise data over RPC, they’re often one of the few options available to you. GWT-RPC is a case in point, and the reason for the Grails DTO plugin. Gilead allows you to transparently serialise Hibernate domain instances, but this only works if the domain class can be loaded by the client. Since GORM domain classes are typically Groovy, that’s not an option with GWT. Your typical Grails domain class also includes a bunch of stuff that the client is hardly going to be interested in, like the custom mappings. So we need a set of Java classes that the client can access – in other words, DTOs.

So what are the main issues with DTOs? First of all, you have to write them. In fact, you pretty much end up duplicating your domain classes! There’s little that’s more depressing. Second, you have to write code to copy the data from your domain instances to DTO instances. When done manually, this can be particularly error-prone as well as laborious.

What if we can mitigate those issues? That’s what the DTO plugin is for. It provides two features that can eliminate the labour involved with creating and maintaining DTOs. Let’s look at the first one.

Creating DTO classes

Your average DTO class is a copy of its corresponding domain class, minus all the mapping information and non-transient data. So the plugin provides a command that does this for you:

grails generate-dto org.example.MyDomain
The above will not only create a MyDomainDTO class for you that has the same persistent fields as MyDomain, but it will also create DTO classes for all related classes, such as those declared via hasMany or belongsTo. In fact, if you’re not careful you can end up with DTOs for your whole domain model!

Alternatively, if that’s what you want (DTOs for your whole domain model), then you can use

grails generate-dto --all
More control can be exercised with the --non-recursive option, which disables the default behaviour and means that the command will only create DTOs for the named domain classes. In other words, it doesn’t follow the relations.

Of course, once you have generated the DTO classes, you don’t have to stop there. If you want to limit the amount of information that will be transferred to a client, simply edit the classes and remove any fields or relationships you want. Or replace relations with a different field. For example, you may not want to return a whole user object associated with a blog post, but you might want to send the user ID or the username.

Generating the DTO classes is only half the story, though. You have to actually convert the domain instances returned by queries and the like into DTO instances.

Converting domain instances to DTOs

It’s possible to do the conversion manually if you want. You could even use Apache Commons or Spring to copy the fields from one object to another. But why? The plugin makes it easy to do the conversion by applying some Groovy magic. Given a domain instance, simply use one of the following options:

def post = Post.get(somePostId)
def dto = post as DTO

// or
dto = post.toDTO()

The first option, as DTO, fits in nicely with the look and feel of Grails converters, but you do have to remember to import the grails.plugins.dto.DTO class. The second option doesn’t require the import, but doesn’t look quite as funky either.

With the soon-to-be-released version 0.1.2 of the plugin, you can also serialise collections and maps of domain classes:

def posts = Post.findAllByCategory("music")
def dto = posts as DTO

That’s all there is to it. However, one thing to bear in mind is that things get more complicated if you edit the DTO classes. In such cases, you probably need to provide some custom mappings to ensure that the data is copied correctly. I’ve not tried it myself, but since the domain instance -> DTO mapping is done by Dozer, you should be able to provide a Dozer mapping file. Once thing I would like to add in future is easy custom mappings using Groovy instead of the Dozer XML files. ‘Til then, it’s XML I’m afraid.

For those people who find themselves in need of DTOs for whatever reason, I hope this plugin makes your lives just a bit easier. Happy coding!

Idiot’s guide to signing up for Yahoo! Groups

It seems fairly clear that Yahoo! doesn’t have the most intuitive user interface, so here are some instructions that I hope will help people get signed up for Yahoo! Groups with the minimum of fuss. It’s intended for members of my rowing club, Furnivall, but if it works for others, great!

  1. Go to the Yahoo! Groups web page, and click on the Sign Up link
  2. Sign Up link on Yahoo! Groups home page

    Sign Up link on Yahoo! Groups home page

  3. Fill in the form that’s displayed. Don’t forget to tick the checkbox at the end of the form to say you’ve read the terms and conditions! Then click on the “Create My Account” button.
  4. Sign up form

    Sign up form

  5. You will return to the Yahoo! Groups home page. In the top left corner, you will see your username. Hover the mouse over it and select “Account Info” from the drop-down menu.
  6. Yahoo! Groups home page when signed in

    Yahoo! Groups home page when signed in

  7. Yahoo! will ask you for your username and password again (it’s just an extra security step). Enter them and you will be transported to the Account Info page. From here, you will see one or more e-mail addresses. Click on the “Change” link as highlighted in the next image.
  8. Account Info page

    Account Info page

  9. On the next page, you can add or remove e-mail addresses. If you want e-mail from a group to go to a particular e-mail address, and that address is not shown on this page, click on the “Add Another” link.
  10. Adding and removing e-mail addresses

  11. You can now join a group, for example by going back to the home page and searching for the name of the group you want to join. One last thing: changing the e-mail address that the group sends e-mails to. Go to the home page of the specific group you want to configure and click on the “Edit membership” link.
  12. A group home page

  13. From the group membership page, you’ll see that you can select any one of the e-mail addresses you configured earlier. You can also hide your e-mail address if you want.
  14. Edit group membership page

    Edit group membership page

    Now go sign up to those Yahoo! groups!