2
votes

Grails 2.3.4

Given the following domain class:

class Player {

    String name

    static constraints = {
        name nullable: false, size: 2..30, unique: true
    }
}

Running the following unit tests produce some strange behavior.

Testing using shouldFail()

@Test
void nameUniqueContraint() {
    Player player = new Player(name: "John")
    Player player2 = new Player(name: player.name)
    assert(player.save())
    shouldFail(ValidationException) {
            player2.save(failOnError: true, flush: true)
            fail "FAIL ME"  
    }
}

Test result:

grails.validation.ValidationException: Validation error occurred during call to save():

  • Field error in object 'moonillusions.sulis.domain.Player' on field 'name': rejected value [John]

Testing using shouldFail() and catch

@Test
void nameUniqueContraint1() {
    Player player = new Player(name: "John")
    Player player2 = new Player(name: player.name)
    assert(player.save())
    shouldFail(ValidationException) {
        try {
            player2.save(failOnError: true, flush: true)
            fail "FAIL ME"
        }catch(ValidationException e) {
            fail "CATCHED "
        }
    }
}

Test result:

junit.framework.AssertionFailedError: CATCHED

Testing using catch

@Test
    void nameUniqueContraint2() {
        Player player = new Player(name: "John")
        Player player2 = new Player(name: player.name)
        assert(player.save())
        try {
            player2.save(failOnError: true, flush: true)
            fail "FAIL ME"
        }catch(ValidationException e) {
            fail "CATCHED "
        }
    }

Test result:

junit.framework.AssertionFailedError: FAIL ME

For me these results do not make any sense. shouldFail() seems not to behave us expected (test 1) and also affecting the try block (test 2) inside the code.

1
I'm experiencing a similar thing on 2.3.5. It seems like shouldFail is running the code provided after terminating without an exception. What leads to just throwing the original exception without any special handling. Did you find any solution for this? - amit
What is the parent class of your test? - Jeff Scott Brown

1 Answers

0
votes

This behaviour is somehow related to the flushing of the first "player" in the example. Likely the flushing for the first players is happening when the second players is flushed. Thus it will, in my understanding, cause two validation exceptions to take place.

Solution was to flush the first player at the start of the test.

@Test
void nameUniqueContraint() {
    Player player = new Player(name: "John")
    Player player2 = new Player(name: player.name)
    assert(player.save(failOnError: true, flush: true))
    shouldFail(ValidationException) {
            player2.save(failOnError: true, flush: true)
    }
}