使用会话和控制器实例测试POST请求。

时间:2016-06-12 15:17:24

标签: java scala session testing playframework

我正在尝试测试我的Play应用程序控制器,但我很难找到让测试在使用控制器实例的同时返回两个会话数据。

public class HomeControllerTest extends WithApplication {

    @Override
    protected Application provideApplication() {
        return new GuiceApplicationBuilder()
            .configure("play.http.router", "router.Routes")
            .build();
    }

    @Test
    public void testGameChoiceHvH() {
        Map form = new HashMap<String, String>();
        form.put("gameType", "0");
        HomeController homeController = new HomeController();
        Result result = invokeWithContext(fakeRequest().bodyForm(form),
            () -> homeController.chooseGame());
        assertEquals(SEE_OTHER, result.status());
        assertEquals("/play", result.header("Location").get());
        assertFalse(result.session().isEmpty());
        String gameId = result.session().get("game_id");
        assertTrue(homeController.getGame(gameId).getCurrentPlayer() instanceof Human);
    }

}

这里的最终断言是模拟将gameId存储在会话中并使用它检索游戏实例,在控制器动作中创建并存储在控制器实例内的Map中。问题是通过使用invokeWithContext,result根本不包含Cookie对象,因此无法检索它。

我发现创建帖子请求的替代方法如下:

public class HomeControllerTest extends WithApplication {

    @Override
    protected Application provideApplication() {
        return new GuiceApplicationBuilder()
            .configure("play.http.router", "router.Routes")
            .build();
    }

    @Test
    public void testGameChoiceHvH() {
        Map form = new HashMap<String, String>();
        form.put("gameType", "0");
        HomeController homeController = new HomeController();
        Result result = route(fakeRequest(routes.HomeController.chooseGame()).bodyForm(form));
        assertEquals(SEE_OTHER, result.status());
        assertEquals("/play", result.header("Location").get());
        assertFalse(result.session().isEmpty());
        String gameId = result.session().get("game_id");
        assertTrue(homeController.getGame(gameId).getCurrentPlayer() instanceof Human);
    }

}

然而,这显然意味着最终断言正在查看HomeController的新实例,而不是route函数使用的实例,因此,Map是空的。

为清楚起见,这里是相关的控制器代码:

public class HomeController extends Controller {

    private WebInterface ui = new WebInterface();
    private Map<String, Board> boardMap = new HashMap<>();
    private Map<String, Game> gameMap = new HashMap<>();

    public Game getGame(String gameId) {
        return gameMap.get(gameId);
    }

    public Result chooseGame() {
        Map<String, String[]> request = request().body().asFormUrlEncoded();
        Board board = new Board();
        Game game = new Game(new PlayerFactory(ui).create(GameType.values()[Integer.valueOf(request.get("gameType")[0])]));
        boardMap.put(Integer.toString(board.hashCode()), board);
        gameMap.put(Integer.toString(game.hashCode()), game);
        session("game_id", Integer.toString(game.hashCode()));
        session("board_id", Integer.toString(board.hashCode()));
        return redirect("/play");
    }

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

因此,经过长时间寻找解决方案后,我在源代码中找到了答案:

/**
 * Calls a Callable which invokes a Controller or some other method with a Context
 */
public static <V> V invokeWithContext(RequestBuilder requestBuilder, Callable<V> callable) {
  try {
    Context.current.set(new Context(requestBuilder));
    return callable.call();
  } catch (Exception e) {
    throw new RuntimeException(e);
  } finally {
    Context.current.remove();
  }
}

基于此信息,现在很明显为什么invokeWithContext在运行后不会公开上下文。因此,作为解决方案的快速而肮脏的实现:

@Test
public void testGameChoiceHvH() {
    Map form = new HashMap<String, String>();
    form.put("gameType", "0");
    HomeController homeController = new HomeController();

    Http.RequestBuilder request = fakeRequest(routes.HomeController.chooseGame()).bodyForm(form);
    try {
        Http.Context.current.set(new Http.Context(request));
        homeController.chooseGame();

    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {

        assertFalse(Http.Context.current().session().isEmpty());
        String gameId = Http.Context.current().session().get("game_id");

        assertTrue(homeController.getGame(gameId).getCurrentPlayer() instanceof DelayedComputer);

        Http.Context.current.remove();
    }
}

这会公开session和homeController实例,因此可以测试断言。