Geb + Spock = A cure for all your testing ills

November 12th, 2010 by dwf

Back in an earlier post, I got a comment from Peter Ledbrook (coauthor of Grails in Action), suggesting that I use Geb and Spock for functional testing. Here’s the comment again, to save looking it up (and also because the software that suggests blog links is a bit flummoxed by the names “Geb” and “Spock”, as you might have gathered):

“I recommend looking at Spock and Geb for functional testing (best for access control and the like). You can see an example in some of my Shiro plugin tests. You’ll find the page objects in the ‘pages’ sub-directory.

You’ll need to run:

grails install-plugin geb
grails install-plugin spock 0.5-groovy-1.7-SNAPSHOT

then be sure to read the chapter in the Geb manual on Grails integration.”

Well, that turned out to be just what I wanted. I’m still getting the hang of the new syntax (it’s a bit tricky trying learning two new things at once, as I’m easily confused…). But it’s well worth the effort – and by looking at the example code given in the link above (not to mention some judicious copying and pasting), you can get useful tests going in a few minutes.

What happens when you run a test is that a web browser instance is started up, and pages are visited according to your instructions. You can specify what data is entered in which text boxes, which buttons are clicked, and so on. And then you can see if you ended up on the right page, or the right messages are displayed. You can login in as different users with different access rights, and see if the expected behaviour actually happens.

Not much more to be said really – great piece of advice, and very useful software. I’ve already unearthed and fixed a couple of minor flaws in the code – I just need to add tests for as much of the other behaviours as I can.

Enhanced by Zemanta

Multiple select with Grails

October 28th, 2010 by dwf

Again, the usual apologies for neglecting the blog – it seems to be the first casualty when I have lots of other things to do.

Today’s tale of woe (I’m starting to feel like Denis Norden with his clipboard) relates to using the <g:select> tag in Grails, and processing the selected item(s).

In a GSP file, I have:

<g:select optionKey="id" from="${potentialResearchers}" name="add_researcher_id" optionValue="userRealName" multiple="yes" size="10" style="width:200px;"/>

This is based on an older version, which didn’t use multiple selection. This select is for adding researchers to an intervention folder, and it can be a chore to select one researcher, click a button, select another, and so on. So, we want to add a whole bunch in one go.

Well, it quickly became apparent that there was an issue in the controller, where we try to process what comes out of the form. If you select more than one item in the form, a list is passed in the parameters. But, if you select just one item, you don’t get a list – just the item itself. Well, to me, passing a list of one element would seem far more sensible – but no problem, I can turn everything into a list first, and then process it.

So, version one of the addResearcher method in the controller:

def addResearcher = {

// ...
def researcherIDs = params.add_researcher_id as List
def researchersToAdd = researcherIDs.collect { User.get(it) }

//...

This all seemed perfectly reasonable – and it works as long as you have less than ten items in your collection of researchers (or more precisely, all the IDs of the researchers have single digits…). For example, if you select researchers with IDs 1, 4, and 6 – you get a list passed, and researchersToAdd is ['1','4','6']. And if you just select researcher with ID 6, it’s ['6'].

But, when you have a researcher with ID larger than 9, and you just select that one researcher, you get problems. For example, you select researcher #637. The value of params.add_researcher_id is the string “637″ – and “as List” converts Strings into lists of their individual characters (which I hadn’t anticipated). So, researchersToAdd becomes ['6','3','7'], with bad results…

After a bit of searching on the web, I found that someone else had a neat solution, so we now have the second (and hopefully final) version:

def addResearcher = {
//...

def researcherIDs = params.add_researcher_id // might be list or single string
def researcherIDlist = (researcherIDs)?[researcherIDs].flatten():null // now it's a list
def researchersToAdd = researcherIDlist.collect { User.get(it) }

//...

This converts the researcherIDs into a list by the square brackets. Of course, if it was a list to begin with, it will now be a list-of-a-list (e.g. [['1','4','6']] ). So flatten() is used to remove that.

Lesson learned this week: make sure you test with large amounts of data, not just the half dozen sample researchers that you created in the Bootstrap.groovy file. What we do now is make a dump of the actual production database, and copy it over to the development database. It’s a bit of a chore, but well worth it. You really only need to do the dump once – I used the mysqldump command for that. See this article for all you need to know – and I’m sure there are utilities that can be used for other databases or if you don’t like using the command line.

Enhanced by Zemanta

Gotcha! Part II

September 24th, 2010 by dwf

Sorry for neglecting the blog (again). Doing a two-parter seemed like a good idea at the time, but it seems to have become a bit of a millstone.

Just to recap, last time I described a problem that came up when I was experimenting with a simple tagging system for interventions. When I tried to retrieve interventions with a particular tag, I found the interventions, but all the other tags for those interventions had strangely disappeared.

It took quite a bit of searching before I found any mention of the same issue. There’s a very good description here, but I haven’t been able yet to get a clear understanding of what the underlying mechanism is. And the solution in that article (querying from the other side of a bidirectional association) won’t work in my case, as tag objects don’t “know about” what they are tagging. I got my toy example working by adding interventions*.refresh() after doing the query, but that’s presumably going to introduce some performance overheads.

It seems a bit lame to leave the problem without a neat solution, but I’ll keep it on the back burner, and maybe return to it in a later post. Just to try to get some conclusions though, it seems that I was labouring under the assumption (quite a reasonable one, I think) that retrieving an object won’t alter that object. I was also thinking of the whole GORM/Hibernate mechanism that Grails uses to stored objects in a database as a black box, without wanting to know anything about the internal workings. Objects go in, objects come out, and everyone’s happy. Until the objects come out looking different from when they went in… This sort of violated assumption can be pretty annoying, but it’s often the start of a new learning curve. And there’s always new stuff to be learned.

Enhanced by Zemanta

Gotcha! part I

September 3rd, 2010 by dwf

Sorry for the lack of updates – I was away on holiday, and had lots to do when I got back. In fact, I’ve still got lots to do, so this will have to be a two-parter, which I’ll finish when I have time (hopefully next week).

To set the scene, I was experimenting with adding tags to interventions in IBBRE. This would allow users to group related interventions by giving them a common tag. In the end, we decided to go a different route, but I found an interesting problem while a tried a basic implementation.

Here’s the top few lines of the Intervention.groovy class:
class Intervention {
String shortName;
String longName;
Date deployedDate;
static hasMany = [tags:Tag]

So an intervention can have multiple tags. At some point I’d like to be able to find out which interventions have a particular tag, and list them. So, a bit further down in the same file, I tried:

def static withTag(String tagName) {
def interventions = Intervention.withCriteria {
tags {
eq('name', tagName )
}
}
}

(Getting indentation to show up correctly is beyond my blogging skills just now…) Anyway, this did the job of finding the correct interventions, but when I listed them out, displaying the tags as well, only the searched-for tags were shown. I.e. somewhere else in a controller, there was a line like this:

def taggedInts = Intervention.withTag( name )

But when I tried listing the tags contained in each of taggedInts, there was only ever one (name). All the others had silently disappeared, which was a nuisance, and a mystery.

OK, as I said, I have to keep this short today. Suffice it to say, with a bit of searching, I found what was causing the problem, and how to fix it. But that’ll have to wait for next time.

Testing times

August 13th, 2010 by dwf

In last week’s post, I described some mistakes and blunders that I had made while writing code for IBBRE.

It seems clear what the main lesson is – I need to do more testing before updating the main server. I can try running the system on my local machine, or on the “beta” server that we use for making new functionality available before unleashing it on the whole IBBRE community. But these will not get the extensive use that the main server receives.

Possibly the most common problem that we get is access control. Different users are allowed to access different parts of the site, with admin users being able to access everything, and regular users able to access just the basics. There are a couple of other access levels in between: researcher and moderator. The main testing procedure is just to log on as these user types on a test server, and see if the new functionality is available or not. But if you’re in a hurry, it’s easy to forget one of the user types. I suspect that we are usually erring on the side of caution, as I will always log in as an admin, and see that it’s possible to do the new function X (which is intended for all users), but forget to log in as a regular user. But if there’s an admin-only function, then I’ll automatically be more careful. But that’s no real excuse, of course.

The best solution would be to automate these tests using the Grails testing framework. The book “Grails in Action” by Smith and Ledbrook has a good chapter on access control (ch. 10) including how to test it. It’s my new year’s resolution (or Friday 13th resolution at least…), to automatically test the access control on new functionality from now on.

And finally, I think testing should be planned for from the start. It’s very easy not to do testing properly, either because it seems like a chore compared to writing code, or because there never seems to be enough time. But possibly the main reason that there’s not enough time is because you have to spend lots of time fixing old code…? Either way, I think that testing and documenting should be built into the project plan, with enough time allocated to do it, and some deliverables to make sure that it’s done. And the tests should probably be written up front: test driven development.

Next week, I’ve got some more Grails gotchas that I found this week. Note: gotchas, not mistakes – as the behaviour that I expected (but didn’t get), seemed very reasonable to expect…

Enhanced by Zemanta

IBBRE

August 6th, 2010 by dwf

Welcome to the first in what should be a series of posts about the IBBRE project. I’m David Fowler, one of the IBBRE software developers. I haven’t really been given any specific remit as to what to blog about, so I’m going to talk about what I find interesting – which this week will be about the knowledge required to keep IBBRE up and running. I joined the project a few months ago, and was faced with a large amount of existing code to be worked with and added to. There was a steep learning curve in figuring out how all this worked, and I shall use examples from my own experience where possible for illustration.

What I plan to do today is just give a couple of examples of where things have gone wrong (ok, they were fixed fairly quickly, but should have been spotted in testing). In future posts, I’ll try to draw some conclusions.

First some background information which may help to understand the later examples. The IBBRE server (what you interact with when you go to http://www.lifeguideonline.org) is written using Grails. If you’ve done any programming before, I can recommend going to http://www.grails.org/Community, downloading Grails, and working through the tutorials. Otherwise, or if you’re pressed for time, hopefully the following explanation will help.

The G in Grails stands for Groovy, a Java compatible scripting language. Rails is a web development framework. I guess the easiest way to explain Rails is that it’s a set of conventions, or best practices, which help you design web systems in a straightforward way. The main convention is that of Model, View, Controller (MVC) which forces you to separate the data itself (the model) from how the data is displayed (the view), and from the actions that alter the data (the controller). The main resaon for all this is that by separating the different elements, the resulting code is easier to understand and maintain. In IBBRE we have a model describing intervention data held in a file Intervention.groovy, with a controller called InterventionController.groovy, and several views (for the creation, editing, listing, etc, of interventions). Views are written in GSP (basically HTML with some extra features). All these files are stored in a directory structure, and as long as you know the conventions, it’s fairly easy to find the bit of code that does a particular job.

Another important feature is that the models (i.e. the data descriptions) map to database tables, so that if you create a new intervention in InterventionController, it will be saved as a row in a table in the database. This mapping process is called GORM (Grails Object Relational Mapping) and saves a lot of effort on the part of the programmer. A very useful feature is that if you modify the model, the database gets updated (maybe extra columns are added to a table), with no extra work needed from the programmer.

I want to describe a couple of issues that can catch out a novice user (e.g. me). When you’re developing and testing new code, you don’t want to use the main database that holds all the important intervention data. One mistake would result in a deluge of irate emails and loss of confidence from the end users. So we use a local Grails server with a local database, which is typically wiped when the server is restarted. In order to avoid having to enter sample test data every time, there is a file Bootstrap.groovy that adds all this when the server starts. Now, even though it sounds really obvious when I say it, it’s very easy to add some code to this bootstrap file, see that the new data appears on the development server – and then completely forget to modify the main database when the time comes to update the main server.

A case in point with IBBRE is access permissions. We have a database table called requestmap which specifies which types of user can access which URLs. A couple of entries in this table are shown in the next figure. The first row says that moderators can make new announcements, and the second says that any user can list tutorial interventions.

+----+------------------+--------------------------------+
| id | config_attribute | url |
+----+------------------+--------------------------------+
...
| 12 | ROLE_MODERATOR | /admin/announcement/** |
...
| 19 | ROLE_USER | /manager/intervention/listTutorial/** |
+----+-------------------+-------------------------------+

In the Bootstrap.groovy file there are lines that add these to the development database (but not to the main database, as that database isn’t wiped between restarts). Something like this:

new Requestmap(url: '/manager/intervention/listTutorial/**', configAttribute: defaultRole).save()

So, it’s easy to get the development version working, create some tutorial interventions, log in as different users, check that everything works as expected, and add the code to the main server. But, you also have to manually add the row to the database table (which I forgot, of course). And eventually, someone will complain getting an error message when they try to look at tutorial interventions.

A second, related, example is also to do with access permissions. In addition to the checking of the requestmap table, there are various places in the code that check that the logged in user has the correct permissions. For example (and don’t worry if you don’t understand the code, I’ll explain it below):

if (intervention.owner.id!=userid &&
!isResearcher &&
!userIsAdministrator &&
!(intervention.type.id == InterventionType.findByName("demo").id) &&
!(intervention.type.id == InterventionType.findByName("tutorial").id)
)
{

This is a test to see if the logged in user has certain permissions (in fact, it’s checking if they don’t have certain permissions, and will output a warning message if not). It looks to see if (a) the user is not the owner of the intervention (b) the user is not a researcher (c) the user is not an admin (d) the intervention is not a demo intervention (e) the intervention is not a tutorial intervention. If all of these are true (i.e. the user fails all the checks), then subsequent code (not shown here) will give the warning.

Why is this important? Well, if you’ve been asked to add a new category of interventions (similar to demo or tutorial), you have to remember to add a line to the test. (And of course, when I recently added the tutorial category, I omitted to add the line:

!(intervention.type.id == InterventionType.findByName("tutorial").id)

And why did I forget? Because I had added the row to the requestmap table, logged in to the server and checked to see if everything worked. But when I logged in to check it, it must have been as either an admin or the intervention owner, as there was no warning message. Easy to do if you’re in a hurry, I guess. But also, because I had taken the action to add the requestmap entry that lets all users look at interventions, I assumed that there wasn’t anything else to do. But the main lesson is that you should log in as every possible type of user, and owner or non-owner of the intervention, before accepting the code as OK.

OK, I’ve made myself look stupid enough for one day… Next time, I’ll try to draw some conclusions – and maybe add some more examples as I think of them (or if I manage to make some new real life ones).

Enhanced by Zemanta