열심히 작성한 인수 테스트가 사실 무의미한 테스트라면 어떨까요? 문제가 발생했을 때 테스트에서 감지할 수 있도록 유의미한 인수 테스트를 작성하는 방법에 대해 알아봅시다.

의미 없는 테스트

의미 없는 테스트는 어떤 테스트를 말하는 것일까요? 저는 다음과 같은 테스트라고 생각합니다.

@Test
void test {
    Member member = new Member("test@email.com", "test");

    assertThat(member).isNotNull();
}

위와 같은 테스트는 Member 인스턴스를 생성한다는 동작에 대하여 결과를 구체적으로 검증하고 있지 않습니다. 따라서 인스턴스를 생성하는 동작에 변경 사항이 있더라도 감지하지 못하고 항상 성공해버립니다. 그렇다면 의미 있는 테스트는 어떻게 작성할 수 있을까요?

유의미한 테스트가 되기 위해서

행위에 대한 결과를 검증해야한다

@Test
void test {
    Member member = new Member("test@email.com", "test");

    assertAll(
            () -> assertThat(member.getEmail()).isEqualTo("test@email.com"),
            () -> assertThat(member.getPassword()).isEqualTo("test"),
            () -> assertThat(member.getRole()).isEqualTo(MemberRole.MEMBER)
    );
}

의미있는 테스트를 작성하기 위해선 인스턴스의 상태를 검증하는 등 행위에 대한 결과를 구체적으로 검증해야합니다. 첫 번째 코드와 달리 두 번째 코드는 인스턴스를 생성하면 기본적으로 MEMBER라는 역할 또한 생긴다는 것을 확인할 수 있습니다.

변경을 감지할 수 있다

만약, 회원 가입 시 회원의 역할을 MEMBER가 아닌 ADMIN으로 설정해준다면 테스트 코드는 실패하게 되고 행위에 대한 결과가 변경되었다는 것을 테스트 코드 수준에서 쉽게 알 수 있습니다.

인수 테스트를 작성하는 방법

인수 테스트는 클라이언트의 요청에 대한 응답을 검증하는 테스트입니다. 이때 인수 테스트는 철저하게 클라이언트의 시각에서 작성되어야합니다.

Restful API를 사용하는 클라이언트는 서버의 내부 로직을 알지 못해도 원하는 기능을 사용할 수 있습니다. 따라서, 인수 테스트는 production code 없이 순수하게 작성되어야합니다. 지금부터 그 이유에 대해 좀 더 자세히 알아보도록 하겠습니다.

Production code를 의존한 인수 테스트

예를 들어 회원 가입에 대한 인수 테스트를 다음과 같이 작성했다고 가정해봅시다.

public record SignUpRequest(String email, String password){}
public record SignUpResponse(String result){}
@Test
void signUp() {
    final String result = RestAssured.given()
            .contentType(APPLICATION_JSON_VALUE)
            .body(new SignUpRequest("test@email.com", "test")
            .when()
            .post("/members")
            .then()
            .statusCode(201)
            .extract().body().as(SignUpResponse.class);

    assertThat(result).isEqualTo("success");
}

위 코드는 적절한 인수 테스트인 것처럼 보이지만 의미 없는 인수 테스트입니다. 왜 그럴까요?

수정을 감지하지 못한다

예를 들어, 서버 개발자가 회원 가입 요청 필드가 마음에 들지 않아 passwordpw로 변경했다고 가정해봅시다.

public record SignUpRequest(String email, String pw){}

이제부터 서버에 회원 가입을 요청을 보내기 위해선 다음과 같이 JSON 요청을 보내야합니다.

{
  "email": "test@email.com",
  "pw": "test"
}

서버 개발자가 변경 사항을 유관 부서에 제대로 전달했다면 해피 엔딩이겠죠. 그런데 휴먼 에러로 누락하게 된다면 클라이언트의 회원 가입 요청은 모조리 실패하게 됩니다.

분명히 우리는 클라이언트의 관점에서 서버를 검증하기 위해 인수 테스트를 작성하였으나 변경을 감지하지 못하고 검증에 실패하였습니다. 인수 테스트를 순수하게 작성하지 않고 production code를 이용하여 요청 JSON을 생성하고 있었기 때문입니다.

바람직한 인수 테스트

따라서 인수 테스트는 다음과 같이 작성되어야합니다.

@Test
void signUp() {
    RestAssured.given()
            .contentType(APPLICATION_JSON_VALUE)
            .body(
                    """
                    {
                        "email": "test@email.com",
                        "password": "test"
                    }
                    """)
            .when()
            .post("/members")
            .then()
            .statusCode(201)
            .body("result", is("success"));
}

위 같은 경우 DTO의 필드를 변경할 경우 테스트가 실패하게 됩니다. 따라서 서버 개발자는 이를 보고 클라이언트 관점에서 서버에 문제가 생겼음을 확인할 수 있습니다.

자가 테스트

작성한 인수 테스트가 클라이언트의 관점으로 작성되었는지 검증하는 가장 쉬운 방법은 코드의 import문을 보는 것입니다. production package에 대한 import문이 있다면 순수하지 않은 테스트 코드입니다.

Untitled.png

만약 import문이 존재한다면, 해당 코드를 지우고 테스트가 정상적으로 수행될 수 있도록 리팩터링하여 의미 있는 인수 테스트를 작성할 수 있습니다.

마무리하며

이번 글에서는 의미 있는 테스트란 무엇인가에 대해 알아보고 인수 테스트에서 body를 적절하게 작성하는 방법에 대해 알아보았습니다. 테스트 코드를 작성하는 것도 중요하지만 열심히 만든 테스트가 제 역할을 수행하도록 잘 작성하는 것이 무엇보다 중요하다고 생각합니다. 글 읽어주셔서 감사합니다! ☺️

카테고리:

업데이트:

댓글남기기