Saturday, December 14, 2013

Grails 2.3.2 > IllegalArgumentException: No enum constant org.springframework.http.HttpMethod.

I just encountered a pretty benign error that ended up taking me about an hour to resolve.  Since I didn't find any Q&As about this on stackoverflow.com, I figured I should document it in case anyone else runs into it.

So I wrote a simple Spock test for my AccountController.

@TestFor(AccountController)
@Mock([Account])
class AccountControllerSpec extends Specification {
    void "should return account with given identfier"() {
        when:
            def account = new Account(firstName: "Justin", lastName: "Miranda", age: 35).save(flush:true)
            params.id = account.id            
            controller.show()

        then:
            response.json.id == account.id
            response.json.firstName == account.firstName
            response.json.lastName == account.lastName
    }
}

Next, I wrote a simple controller with just a show method.

class AccountController {
    static allowedMethods = [show:"GET"]
    def show(Account account) {
        if (account == null) {
            render status:404
            return
        }
        render account as JSON
    }
}

Then I ran the unit test and received the following error.

grails> test-app unit: AccountController --verbose --stacktrace
| Running 1 unit test... 1 of 1
ID: 1
| Failure:  should return account with given identfier(com.kinectus.AccountControllerSpec)
|  java.lang.IllegalArgumentException: No enum constant org.springframework.http.HttpMethod.
at java.lang.Enum.valueOf(Enum.java:236)
at org.springframework.http.HttpMethod.valueOf(HttpMethod.java:27)
at org.codehaus.groovy.grails.plugins.web.api.ControllersApi.initializeCommandObject(ControllersApi.java:436)
at com.kinectus.AccountControllerSpec.should return account with given identfier(AccountControllerSpec.groovy:24)

Now that I know the solution, the error message is a little more helpful than I originally thought.  The period (.)  after HttpMethod is not the end of the sentence ... it's actually a hint to the answer.  It's saying No enum constant org.springframework.http.HttpMethod.SOMEVALUE.   It really should have only taken a few seconds to figure this out, but I had just spent a good deal of time working with HttpStatus, so I thought the issue was with HttpStatus for some reason.

Anyway, the solution is to add a request method to the test before calling the show controller action.

@TestFor(AccountController)
@Mock([Account])
class AccountControllerSpec extends Specification {
    void "should return account with given identfier"() {
        when:
            def account = new Account(firstName: "Justin", lastName: "Miranda", age: 35).save(flush:true)
            params.id = account.id
            request.method = "GET"
            controller.show()

        then:
            response.json.id == account.id
            response.json.firstName == account.firstName
            response.json.lastName == account.lastName
    }
}

And that's it.