Testy kontrolera logowania, czy mogę coś ulepszyć?

0

Cześć,
mam takie testy dla kontrolera logowania. Zastanawiam się, co mógłbym ulepszyć.

Na ten moment myślałem o dwóch rzeczach:

  1. Może zamiast Testconteiner lepiej byłoby zastosować jakieś in-memory repository na HashMapie.
  2. Myślałem, żeby jakoś przenieś te asercje do osobnej klasy.

Co myślicie, może coś macie do dodania?

@AutoConfigureMockMvc
class LoginControllerTest extends BaseIT {

    @Autowired
    private MockMvc mockMvc;
    @Autowired
    private LoginRequests requests;
    @Autowired
    private UserFixture userFixture;

    @Autowired
    private SqlDatabaseInitializer initializer;
    @Autowired
    private SqlDatabaseCleaner cleaner;

    @BeforeEach
    void setUp() throws Exception {
        initializer.setup("data_sql/test-setup.sql");
    }

    @AfterEach
    void cleanUp() {
        cleaner.clean();
    }

    @Test
    void whenLoginSuccess_ResponseStatusOk() throws Exception {
        createUserWithUsername("Alex");
        assertStatusCode("/api/v1/users/login", requests.login("Alex"), 200);
    }

    @Test
    void whenLoginSuccess_ReturnMessage() throws Exception {
        createUserWithUsername("Alex");
        assertJsonMessage("/api/v1/users/login", requests.login("Alex"),
                "$.message", "Logged successfully.");
    }

    @Test
    void whenLoginSuccess_SetSessionCookie() throws Exception {
        createUserWithUsername("Alex");
        assertCookieExists("/api/v1/users/login",
                requests.login("Alex"), "session_id");
    }

    @Test
    void whenLoginSuccess_SessionCookieNotEmpty() throws Exception {
        createUserWithUsername("Alex");
        assertCookieNotEmpty("/api/v1/users/login",
                requests.login("Alex"), "session_id");
    }

    @Test
    void whenLoginSuccess_CookieIsSetHttpOnly() throws Exception {
        createUserWithUsername("Alex");
        assertCookieHttpOnly("/api/v1/users/login", requests.login("Alex"), "session_id");
    }

    @Test
    void whenLoginSuccess_CookieHasCorrectPath() throws Exception {
        createUserWithUsername("Alex");
        assertCookiePath("/api/v1/users/login", requests.login("Alex"), "session_id", "/");
    }

    @Test
    void whenInvalidCredentials_ReturnUnauthorizedStatus() throws Exception {
        assertStatusCode("/api/v1/users/login", requests.nonExistingUser, 401);
    }

    @Test
    void whenInvalidCredentials_CookieIsNotSet() throws Exception {
        assertCookieNotSet("/api/v1/users/login", requests.nonExistingUser, "session_id");
    }

    @Test
    void whenMalformedJson_ReturnBadRequest() throws Exception {
        assertStatusCode("/api/v1/users/login", requests.malformedJson, 400);
    }

    @Test
    void whenEmptyCredentials_ReturnBadRequest() throws Exception {
        assertStatusCode("/api/v1/users/login", requests.emptyCredentials, 400);
    }
    
    @Test
    void whenEmptyCredentials_ReturnErrorMessage() throws Exception {
        assertJsonErrorMessages("/api/v1/users/login", requests.emptyCredentials,
                "$.errors.usernameOrEmail", "The usernameOrEmail field cannot be empty",
                "$.errors.password", "The password field cannot be empty");
    }

    private void createUserWithUsername(String username) {
        userFixture.createUserWithUsername(username);
    }
    
    private void assertJsonErrorMessages(String endpoint, LoginRequest request,
                                         String firstJsonPath, String firstMessage,
                                         String secondJsonPath, String secondMessage) throws Exception {
        ResultActions actions = mockMvc.perform(post(endpoint)
                .contentType(MediaType.APPLICATION_JSON)
                .content(asJsonString(request)));

        actions.andExpect(jsonPath(firstJsonPath)
                        .value(firstMessage))
                .andExpect(jsonPath(secondJsonPath)
                        .value(secondMessage));
    }

    private void assertStatusCode(String endpoint, LoginRequest request, int statusCode) throws Exception {
        mockMvc.perform(post(endpoint)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(asJsonString(request)))
                .andExpect(status().is(statusCode));
    }
    private void assertStatusCode(String endpoint, String request, int statusCode) throws Exception {
        mockMvc.perform(post(endpoint)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(asJsonString(request)))
                .andExpect(status().is(statusCode));
    }
    private void assertJsonMessage(String endpoint, LoginRequest request,
                                   String jsonPath, String expectedMessage) throws Exception {
        mockMvc.perform(post(endpoint)
                .contentType(MediaType.APPLICATION_JSON)
                .content(asJsonString(request)))
                .andExpect(jsonPath(jsonPath).value(expectedMessage));
    }
    private void assertCookieExists(String endpoint, LoginRequest request, String cookieName) throws Exception {
        mockMvc.perform(post(endpoint)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(asJsonString(request)))
                .andExpect(cookie().exists(cookieName));
    }
    private void assertCookieNotEmpty(String endpoint, LoginRequest request, String cookieName) throws Exception {
        MvcResult mvcResult = mockMvc.perform(post(endpoint)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(asJsonString(request)))
                .andReturn();

        Cookie cookie = mvcResult.getResponse().getCookie(cookieName);
        assertNotNull(cookie);

        String cookieValue = cookie.getValue();
        assertNotNull(cookieValue);
    }
    private void assertCookieHttpOnly(String endpoint, LoginRequest request, String cookieName) throws Exception {
        mockMvc.perform(post(endpoint)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(asJsonString(request)))
                .andExpect(cookie().httpOnly(cookieName, true));
    }
    private void assertCookiePath(String endpoint, LoginRequest request, String cookieName, String path) throws Exception {
        mockMvc.perform(post(endpoint)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(asJsonString(request)))
                .andExpect(cookie().path(cookieName, path));
    }
    private void assertCookieNotSet(String endpoint, LoginRequest request, String cookieName) throws Exception {
        mockMvc.perform(post(endpoint)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(asJsonString(request)))
                .andExpect(cookie().doesNotExist(cookieName));
    }
}
1

Jeśli chcesz testować tyko warstwę HTTP, to na pewno nie potrzebujesz do tego jakiejkolwiek bazy, nawet takiej w pamięci.Poczytaj o WebMvcTest. Nie wiem po co wstrzykuje Springiem LoginRequests i UserFixtures. To mogły by być zwykłe klasy utilsowe ze statycznymi metodami. Zrezygnowałbym z tych prywatnych method też, bo żeby dowiedzieć się jak one działają to i tak trzeba zjechać w dół do ich implementacji. Za dużo abstrakcji to to samo co za mało abstrakcji.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.