Tuesday, 8 March 2011

Testing your Play! controllers

Lets say you have a controller like this (from the Play! documentation)

package controllers;
 
import java.util.*;
 
import play.*;
import play.mvc.*;
 
import models.*;
 
public class Application extends Controller {
 
    public static void index() {
        Post frontPost = Post.find("order by postedAt desc").first();
        List olderPosts = Post.find(
            "order by postedAt desc"
        ).from(1).fetch(10);
        render(frontPost, olderPosts);
    }
 
}

And you want to write a test to check the render parameters are correct, how do you do that?

Well here is a little example
public class ApplicationTest extends FunctionalTest{
 @Before
 public void before() {
  Fixtures.deleteAllModels();
  Fixtures.load("data.yml");
 }

 @Test
 public void testHomePageFirstPost() throws MalformedURLException {
  // Call the home page
  Response response = GET("/");
  
  // Verify that Matches.matchCreate() passed correct params to render().
  Post frontPost = (Post) getRenderParameter("frontPost");
  assertEquals(${value_from_yml}, frontPost.author.fullname);
  assertEquals(${value_from_yml}, frontPost.postedAt);
 }

 /**
  * Gets the parameter that was passed to render() method.
  * @param key
  * @return
  */
 public static Object getRenderParameter(String key) {
  RenderArgs current = Scope.RenderArgs.current();
  return current.data.get(key);
 }

}

You might want to put the getRenderParameter in a separate class to easily reuse it.


If you want to test a controller method that take parameters is as easy.

Let's assume you want to test a simple controller method in Users called getUserByUsername to make sure the correct user is added to render when the form is submitted

public class Users extends Controller {
 
 /**
 * Gets the user given his username
 */
    public static void getUserByUsername(String username) {
        Assert.notNull(user);
        User currentUser = User.find("byUsername", username).first();
        render(currentUser);
    }
 
}



In this case the test would be

public class UserLoginTest extends FunctionalTest{

 @Before
 public void before() {
  Fixtures.deleteAllModels();
  Fixtures.load("users.yml");
 }
 
 @Test
 public void testGetByUsername() {
  Map<String, String> params = new HashMap<String, String>();
  params.put("username", "user1");
  Response response = POST("/users/getbyusername", params, new HashMap<String, File>());
  User currentUser = (User) getRenderParameter(&quot;currentUser&quot;);
  assertEquals(${from_users.yml}, currentUser.name);
  assertEquals(${from_users.yml}, currentUser.email);
 }
}


Please feel free to comment!

Thanks

2 comments:

Dominik Dorn said...

the ${from_users.yml} isn't really in the code, right?

mericano1 said...

That's right. You need to have some data in the db.
I'm using Fixtures.load("users.yml"); to do that.
Let's assume your users.yml looks like this

user(user1)
name: myUser1
username: user1
email: myUser1@email.com

user(user2)
name: myUser2
username: user2
email: myUser2@email.com

Then you need to replace ${from_users.yml} with 'myUser1' in the first line and 'myUser1@email.com' in the last line.

Hope this clarifies.