Friday, August 9, 2013

Groovy moonlighter mistake: Not all "method chaining" does what you might think


Setup
I am using Spock to help inject Groovy into our project and currently that means testing our new RESTful API.   We need to be able to send and receive both XML and JSON.    To test our POST method, I created a default Cart object and get the JSON representation.   I decided to try to use curl to call some of the methods, so for this POST method call, I needed to save the JSON to a file.  Later, I wanted to make sure the file was created.

Problem Code
The code below gets a NullPointerException calling the exists() method.

public void "POST Creates New Cart with JSON"() {
   when:
   File f = new File("cart.json").write(getDefaultCartJSON())
   
   def response = '''curl -X POST -i -d @cart.json --header "Content-Type:application/json"
          http://localhost:7001/restservices/carts'''.execute().text
  
    then:
    f.exists()
    response.startsWith("HTTP/1.1 201 Created")
  }
}

Root Cause:
The problem wasn't obvious immediately to me (hey I wrote it!).  The problem is the write() method returns a void, not the file object.

 File f = new File("cart.json").write(getDefaultCartJSON())

Corrected Code
Below is the corrected code.  So you don't always need to assign the result of a 'new' into a variable, even though that's how many of us learned to program.

public void "POST Creates New Cart with JSON"() {
   when:
   new File("cart.json").write(getDefaultCartJSON())
   
   def response = '''curl -X POST -i -d @cart.json --header "Content-Type:application/json"
          http://localhost:7001/restservices/carts'''.execute().text
  
    then:
    new File("cart.json").exists()
    response.startsWith("HTTP/1.1 201 Created")
  }
}

Wrap-up
Obviously this was not some major problem or break-through, just something to keep in mind as you write your code.   Maybe this will help prevent others from making the same mistake(s) I made. :-)

Hope it helps!

No comments:

Post a Comment