Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing controller with fake session

I want to write test for my controller:

Result changeAction = callAction(controllers.routes.ref.Users.changePassword());
assertThat(status(changeAction)).isEqualTo(OK);

I have a http status code - 300.

That's right it is redirect because I have a class named Secured

package controllers;

import play.mvc.*;
import play.mvc.Http.*;

public class Secured extends Security.Authenticator {

    @Override
    public String getUsername(Context ctx) {
        return ctx.session().get("userId");
    }

    @Override
    public Result onUnauthorized(Context ctx) {
        return redirect(routes.Users.login(ctx.request().uri()));
    }


}

And when I use the @Security.Authenticated(Secured.class) annotation for controller method it redirects if session with "userId" do not exists.

So the question is, how can I fake the session?

I tried obviously call Controller.session("usderId", "2");

And got an exception:

java.lang.RuntimeException: There is no HTTP Context available from here.

    at play.mvc.Http$Context.current(Http.java:30)
    at play.mvc.Controller.session(Controller.java:54)
    at play.mvc.Controller.session(Controller.java:61)
    at controllers.UsersTest.testUnloginedChangePassword(UsersTest.java:35)

My question is: How to fake the session for controller?

And one additional question: how to test routes without using deprecated API, like Result result = routeAndCall(fakeRequest(GET, "/change_password")); ?

like image 567
Slow Harry Avatar asked Jun 09 '13 07:06

Slow Harry


People also ask

Can you unit test controllers?

When unit testing controller logic, only the contents of a single action are tested, not the behavior of its dependencies or of the framework itself. Set up unit tests of controller actions to focus on the controller's behavior. A controller unit test avoids scenarios such as filters, routing, and model binding.

What is mock in unit testing?

Mocking is used in unit tests to replace the return value of a class method or function. This may seem counterintuitive since unit tests are supposed to test the class method or function, but we are replacing all those processing and setting a predefined output.

How do you mock in ISession?

Mock<ISession> sessionMock = new Mock<ISession>(); var key = "FY"; int fy = 2020; var value = new byte[] { (byte)(fy >> 24), (byte)(0xFF & (fy >> 16)), (byte)(0xFF & (fy >> 8)), (byte)(0xFF & fy) }; sessionMock. Setup(_ => _. TryGetValue(key, out value)). Returns(true);

How do you implement unit testing?

A typical unit test contains 3 phases: First, it initializes a small piece of an application it wants to test (also known as the system under test, or SUT), then it applies some stimulus to the system under test (usually by calling a method on it), and finally, it observes the resulting behavior.


1 Answers

You can use the withSession(String, String) method of fakeRequest to put things in the Session. Note that this returns a fakeRequest so you can chain that method if you need to put multiple keys in the session.

Your test could then look something like this:

@Test
public void test() {
   running(fakeApplication(), new Runnable() {
       public void run() {
           String username = "Aerus";
           Result res = route(fakeRequest("GET", "/")
                            .withSession("username", username)
                            .withSession("key","value"));
           assert(contentAsString(res).contains(username));
       }
   });
}

Note also that I used the route method and not routeAndCall, the first is the replacement of the deprecated method.

like image 114
Aerus Avatar answered Oct 09 '22 03:10

Aerus