2016-06-12 53 views
0

我正在嘗試測試我的Play應用程序控制器,但我正在努力尋找讓測試在使用控制器實例的同時返回兩個會話數據。使用會話和控制器實例測試POST請求。

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); 
    } 

} 

這裏的最後斷言模擬採取存儲在會話中的遊戲ID,並用它獲取遊戲實例,在控制器動作創建並存儲在控制器實例中的地圖。問題是,通過使用invokeWithContext,result完全不包含Cookie對象,因此無法檢索。

另一種方法我發現創建一個POST請求如下:

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的新實例,而不是一個使用因此,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"); 
    } 

任何幫助將非常感激。

回答

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(); 
    } 
} 

這暴露了雙方的會話,HomeController的情況下,這樣的斷言都可以進行測試。