Grails Testing Alias to Rerun Failed Tests

2009/11/3

A while ago I blogged about my grails testing aliases and how much time they save me.

I’ve made some enhancements to them in the interim that have made them even easier to use.

The most important alias is gtaf, which is short for “grails test-app” for failed tests.

It will search through your test output directory and look for any tests that failed. If it finds any, it will rerun only those tests. Otherwise, it will rerun all tests. That makes it easy to just use gtaf all the time. If any tests fail, it will open them up using Console.app.

If you’re not on OSX, or would like to use something else to view the failed test logs, just modify the testlog alias to do something different.

There are alternative versions of it to only run failed integration tests (gtaif – Grails Test App Integration Failed), failed unit tests (gtauf – Grails Test App Unit Failed) or attach a debugger to the tests as they run (gtadf – Grails Test App Debug Failed).

These aliases, plus most of the rest of my zsh setup, is available on bitbucket. If you haven’t used zsh before and are still using bash, I suggest switching over for the numerous benefits that it gives you.

Here’s the section of zshrc_general that has the grails testing aliases, just add this to your .zshrc/.bashrc and make sure to uncomment the appropriate GRAILS_TEST_LOG_DIRECTORY export if you’re not running grails 1.2 yet:

# grails > 1.2
export GRAILS_TEST_LOG_DIRECTORY=target/test-reports
 
# grails < 1.2
# export GRAILS_TEST_LOG_DIRECTORY=test/reports
 
# after grails-test if there were ERROR messages, you can open those logs with the Console.app using this
alias testlog='for F in `grep -lE "FAILED|Caused\ an\ ERROR" $GRAILS_TEST_LOG_DIRECTORY/plain/*.txt`; do echo ">>> opening" $F; open -a Console $F; done;'
 
# grails-debug-suspend doesn't exist by default, it's a copy of grails-debug with the suspend flag changed to "y" so that
# we can attach a remote debugger before it proceeds past startup
 
# aliases where you can optionally pass in a set of tests to run (or no argument to run all tests in that group)
alias gta=grailsTestApp
alias gtad=grailsTestAppDebug
alias gtau=grailsTestAppUnit
alias gtaud=grailsTestAppUnitDebug
alias gtai=grailsTestAppIntegration
alias gtaid=grailsTestAppIntegrationDebug
 
# aliases that will rerun any failed tests (or all tests if there aren't any failed tests)
alias gtaf=grailsTestAppFailed
alias gtadf=grailsTestAppDebugFailed
alias gtauf=grailsTestAppUnitFailed
alias gtaudf=grailsTestAppUnitDebugFailed
alias gtaif=grailsTestAppIntegrationFailed
alias gtaidf=grailsTestAppIntegrationDebugFailed
 
 
function grailsTestApp() { grailsTest grails "" $1 }
function grailsTestAppFailed() { grailsFailedTests grails "" }
 
function grailsTestAppDebug() { grailsTest grails-debug-suspend "" $1 }
function grailsTestAppDebugFailed() { grailsFailedTests grails-debug-suspend "" }
 
function grailsTestAppUnit() { grailsTest grails -unit $1 }
function grailsTestAppUnitFailed() { grailsFailedTests grails -unit }
 
function grailsTestAppUnitDebug() { grailsTest grails-debug-suspend -unit $1 }
function grailsTestAppUnitDebugFailed() { grailsFailedTests grails-debug-suspend -unit }
 
function grailsTestAppIntegration() { grailsTest grails -integration $1 }
function grailsTestAppIntegrationFailed() { grailsFailedTests grails -integration }
 
function grailsTestAppIntegrationDebug() { grailsTest grails-debug-suspend -integration $1 }
function grailsTestAppIntegrationDebugFailed() { grailsFailedTests grails-debug-suspend -integration }
 
function grailsFailedTests() {
	FAILED_TESTS=''
	for F in `grep -lE "FAILED|Caused\ an\ ERROR" $GRAILS_TEST_LOG_DIRECTORY/plain/*.txt`; do
		FAILED_TESTS="$FAILED_TESTS `echo $F | sed -E 's/.*TEST-(.*)Tests.txt/\1/g'`"
	done;
	echo "failed tests: $FAILED_TESTS"
	grailsTest $1 $2 $FAILED_TESTS
}
 
function grailsTest() {
	echo "Running: $1 test-app $2 $3 || testlog "
    time $1 test-app $2 $3 || testlog
}

I believe that they’ll also work fine as-is in bash, though I haven’t tested them.


There are 7 comments in this article:

  1. 2009/11/3Robert Fischer say:

    bash requires the open bracket of a function declaration to be the last element on the line. Otherwise, you’ll get confusing messages about unexpected end-of-file.

  2. 2009/11/4tednaleid say:

    @Robert – Thanks! That makes sense, so people using bash would just need to change this:

    function grailsTestAppFailed() { grailsFailedTests grails "" }

    to this:

    function grailsTestAppFailed() {
        grailsFailedTests grails ""
    }

    Yet another reason that I like zsh better :).

  3. 2009/11/4Mike say:

    The Grails test-app script also has a built in flag to re-run failed tests. I haven’t used it much, but you might be able to simplify your logic a little bit to find failed tests using:

    grails test-app -rerun

    See http://grails.org/doc/latest/ref/Command%20Line/test-app.html

  4. 2009/11/4tednaleid say:

    Whoops, I didn’t know about that, thanks Mike. They must have added that fairly recently.

    I just gave it a try and the behavior is a little different. It will only run failed tests, and it’s not smart about bailing out if there aren’t any failed test, so it still bootstraps the full environment and says everything was successful, even though no tests were actually run.

    Some people might like that behavior better, but I like being able to run “gtaf” whether or not I have any tests that failed.

    I can see why some might want the alternate behavior, so that it only runs tests if they are failed. If so, the grailsFailedTests function could be modified to this:

    function grailsFailedTests() {
    	grailsTest $1 $2 -rerun
    }

    Thanks for the pointer Mike!

  5. 2009/11/12Brian Doyle say:

    I’m new to Groovy and Grails so this is probably a dumb question, but wouldn’t you want to set your env in your grailsTest function to: -Dgrails.env=test
    Thanks.

  6. 2009/11/12Brian Doyle say:

    Sorry about my previous comment. It looks like the test-app command does that for you automatically.

  7. 2009/11/12tednaleid say:

    @Bryan, yep, test-app by default uses the test environment, but you can override it using the technique you mentioned (I do this in some apps to connect to a different datasource).

Write a comment: