2

Below is my test suite so far for my MVC app. I'm using Spring Security for authorization, and so far have been able to use the @WithMockUser annotation to take care of it in testing (user1 creates games in testCreateNewGame(), and user2 joins one of them in testJoinNewGame()).

I would like to write a test method for the two users playing out a game. This would entail multiple calls to the same controllers coming from the two different users. Is there a simple way to do this with annotations? I would like to avoid passing state back and forth across multiple test methods if possible.

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class WebApplicationTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private UserService userService;

    private static boolean firstUse = true;

    @Before
    public void saveUsers(){
        if (firstUse) {
            User user1 = new User();
            user1.setUsername("user1");
            user1.setPassword("pwd");
            User user2 = new User();
            user2.setUsername("user2");
            user2.setPassword("pwd");
            userService.save(user1);
            userService.save(user2);
            firstUse = false;
        }
    }

    @Test
    @WithMockUser(username = "user1", password = "pwd", roles = "USER")
    public void testCreateNewGame() throws Exception {
        String s = new ObjectMapper().writeValueAsString(new HashMap<String, Integer>(){{put("numPlayers", 2);}});
        mockMvc.perform(post("/game/create")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(s))
                .andExpect(status().isOk())
                .andExpect(content().string(containsString("WAIT_FOR_PLAYERS_TO_JOIN")));
        mockMvc.perform(post("/game/create")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(s))
                .andExpect(status().isOk())
                .andExpect(content().string(containsString("WAIT_FOR_PLAYERS_TO_JOIN")));
    }

    @Test
    @WithMockUser(username = "user2", password = "pwd", roles = "USER")
    public void testJoinGame() throws Exception {
        MvcResult mvcResult = mockMvc.perform(get("/game/list")).andReturn();
        Game[] games = new ObjectMapper().readValue(mvcResult.getResponse().getContentAsString(), Game[].class);
        assert(games.length == 2);
    }
}
user6118986
  • 341
  • 2
  • 15

1 Answers1

1

As the @WithMockUser annotation will use the defined user for the whole test method execution, you can't simulate two users in one test with this annotation.

What you can do is to use the programmatic approach of the Spring Security integration with testing MVC applications like:

// first call in test
mvc
    .perform(post("/game/create")
    .with(user("admin").password("pass").roles("USER","ADMIN")))

// second call in test
mvc
    .perform(post("/game/create")
    .with(user("duke").password("pass").roles("USER")))

For this to work you should remove the @WithMockUser from your test method.

rieckpil
  • 10,470
  • 3
  • 32
  • 56