티스토리 뷰

이번 글에서는 박우빈 님의 "Practical Testing: 실용적인 테스트 가이드"를 보고 테스트 코드에 대한 제 생각을 정리해 보려고 합니다.

 

테스트 코드란?

개발자가 작성한 실제 코드가 제대로 동작하는지 검증하는 코드입니다.

테스트 코드와 관련된 TDD, BDD와 같은 개발 방법론이 존재합니다.

기술을 학습할 때 테스트 코드를 사용하면 여러 가지 경우를 직접 설정해 구체적인 기능을 재밌게 학습할 수 있는 장점도 있습니다.

 

테스트 코드를 작성하지 않으면 발생하는 일

다음은 제가 겪었던 일입니다.
학교에서 사용 중인 프로젝트에 테스트 코드를 전혀 작성하지 않고, 프로덕션 코드 작성 후 postman을 사용해서 성공 및 간단한 예외 케이스만 확인한 후 바로 배포를 했습니다.

당시에는 테스트 코드의 중요성을 못 느껴서 작성하지 않고 진행했는데 지금 와서 보니 오류가 언제 발생할지 모르는 프로젝트가 되었고 개발하는 시간보다 예상치 못한 곳에서 터지는 오류를 고치는 시간이 더 많아졌습니다.

테스트 코드가 없으면 내 코드가 의도한 대로 동작하는지 검증할 방법이 없어 경험과 감에 의존한 채 개발을 진행하게 되고 결국에는 불안정한 서비스가 될 것입니다. 그리고 오류를 배포한 후에 확인할 수 있어서 서비스에 대한 피드백이 늦고, 유지보수가 점점 어려워지며 서비스의 품질이 떨어질 것입니다.

 

테스트 코드를 작성해야 하는 이유

테스트 코드 == 문서화

@SpringBootTest // 서버를 띄워 통합 테스트를 진행
class ProductServiceTest {

    @Autowired
    private ProductService productService;

    @Autowired
    private ProductRepository productRepository;

    @AfterEach // 각 테스트가 끝난 후 실행
    void tearDown() {
        productRepository.deleteAllInBatch();
    }

    @DisplayName("신규 상품을 등록한다. 상품번호는 가장 최근 상품의 상품번호에서 1 증가한 값이다.")
    @Test
    void createProduct() {
        // given
        Product product = createProduct("001", HANDMADE, SELLING, "아메리카노", 4000);
        productRepository.save(product);

        ProductCreateServiceRequest request = ProductCreateServiceRequest.builder()
                .type(HANDMADE)
                .sellingStatus(SELLING)
                .name("카푸치노")
                .price(5000)
                .build();

        // when
        ProductResponse productResponse = productService.createProduct(request);

        // then
        assertThat(productResponse)
                .extracting("productNumber", "type", "sellingStatus", "name", "price")
                .contains("002", HANDMADE, SELLING, "카푸치노", 5000);

        List<Product> products = productRepository.findAll();
        assertThat(products).hasSize(2)
                .extracting("productNumber", "type", "sellingStatus", "name", "price")
                .containsExactlyInAnyOrder(
                        tuple("001", HANDMADE, SELLING, "아메리카노", 4000),
                        tuple("002", HANDMADE, SELLING, "카푸치노", 5000)
                );

    }

    @DisplayName("상품이 하나도 없는 경우 신규 상품을 등록하면 상품번호는 001이다.")
    @Test
    void createProductWhenProductIsEmpty() {
        // given
        ProductCreateRequest request = ProductCreateRequest.builder()
                .type(HANDMADE)
                .sellingStatus(SELLING)
                .name("카푸치노")
                .price(5000)
                .build();

        // when
        ProductResponse productResponse = productService.createProduct(request.toServiceRequest());

        // then
        assertThat(productResponse)
                .extracting("productNumber", "type", "sellingStatus", "name", "price")
                .contains("001", HANDMADE, SELLING, "카푸치노", 5000);

        List<Product> products = productRepository.findAll();
        assertThat(products).hasSize(1)
                .extracting("productNumber", "type", "sellingStatus", "name", "price")
                .contains(
                        tuple("001", HANDMADE, SELLING, "카푸치노", 5000)
                );
    }

 

상품을 등록하는 테스트 코드입니다. BDD 방식(given-when-then)으로 작성했습니다.

상품을 등록하는 기능을 포함해서 전체적인 서비스를 출시하고 유지보수를 해야 한다는 가정을 해보겠습니다. 그렇게 되면 서비스 인수인계를 해야 할 때가 올 것입니다. 서비스를 넘겨받은 개발자는 서비스 코드를 이해하는 시간이 필요한데, 이때 테스트 코드가 도움을 줄 수 있습니다.

 

테스트 코드를 보면 당시 개발자가 어떤 흐름으로 서비스를 구성했는지 알 수 있습니다. 결국 테스트 코드가 있게 되면 서비스를 넘겨받은 개발자는 쉽게 서비스에 적응할 수 있을 것입니다. 그리고 서비스를 유지 보수하는 개발자도 서비스를 더 잘 이해하면서 코드를 작성할 수 있습니다.

 

 

빠른 피드백

 

테스트 코드가 없어 코드를 바로 배포하게 되면 예상치 못한 오류(예외 처리를 하지 않았거나, 유효성 검증을 하지 않거나 등)를 만나게 될 확률이 높습니다. 그렇게 되면 서비스 품질과 서비스에 대한 사용자의 신뢰도가 굉장히 낮아질 것입니다.

 

하지만 테스트 코드를 작성하면 실제 코드가 의도한 대로 동작하는지 바로 확인할 수 있어 예상치 못한 오류를 만날 확률이 낮습니다.

 

 

과감한 리팩토링


테스트 코드가 의도한 대로 동작하면 위 이미지처럼 초록불이 뜨게됩니다. 테스트 코드를 제대로 작성했다는 가정하에, 프로덕션 코드를 과감하게 리팩토링해도 초록불만 확인하면 코드가 제대로 작동하는지 검증할 수 있습니다.

 

실제 코드 작성 -> 테스트 코드 작성 -> 초록 불 확인 -> 리팩토링 -> 초록 불 확인 ..
위 사이클을 반복하면서 서비스를 구축하고 리팩토링 하면, 리팩토링 시간을 단축하고 전보다 클린한 코드를 작성할 수 있을 것입니다.

 

 

안정적인 서비스

테스트 코드를 작성하면 개발자는 언제든지 테스트 코드를 실행해서 실제 코드가 의도한 대로 동작하는지 확인할 수 있습니다.

유지보수하는 과정에서 기존 코드가 수정될 수 있는데 테스트 코드를 실행해서 프로덕션 코드가 잘 작동하는 걸 확인하면 안정적인 서비스를 구축할 수 있을 것입니다. 또한 빠르게 변화하는 소프트웨어의 안정성을 테스트 코드를 통해 보장할 수 있습니다.

 

 

마무리

전에 헥사고날 아키텍처를 도입할 때 테스트 코드 없이 수동으로 테스트를 진행해서 리팩토링을 하기 힘들었던 경험이 있습니다.

제가 생각하기에 개발자에게 중요한 것 중 하나는 자신이 하는 일에서 반복되는 것을 자동화를 통해 시간을 단축하고 실수를 줄이는 게 중요하다고 생각합니다.

 

테스트 코드는 수동으로 테스트한 것을 이른 시간 안에 자동으로 확인해 주기 때문에 좋은 서비스를 개발할 수 있도록 해주는 것 같습니다. 공부하면서 느끼는 거지만 테스트 코드는 정말 필수인 것 같습니다.

 

이 글을 읽고 계신 분들 중 아직 프로젝트에 테스트 코드를 작성하지 않으셨다면 이번 기회에 프로젝트에 테스트 코드를 적용해서 다양하고 좋은 경험을 해보시면 좋을 것 같습니다!
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함