테스트코드-junit

ttomy·2022년 3월 20일
1
post-custom-banner

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

테스트 코드를 작성하는 이유는 무엇일까. 사실 테스트 코드를 작성해본 적이 없는 사람은 테스트코드를 작성하는것만도 오랜 시간이 걸린다. 개발하기도 바쁜데 테스트코드를 작성하는 것까지 시간을 뺏기고,막상 개발에 투자할 시간이 줄어드는 배보다 배꼽이 더 큰 것 같은 이유로 테스트 코드를 작성하지 않고는 한다. 테스트 코드를 작성해야 하는 이유를 알아보자.

안정적 확장을 가능하게 함

기능을 추가하면 추가된 기능이 다른 코드에 어떤 영향을 미치는 끼치는 지 파악해야 한다. 테스트 코드를 통해 특정부분이 변함없이 작동한다는 확신을 얻으며 개발하는 것과 그렇지 않은 것은 안정성,트러블슈팅의 유용함에서 큰 차이를 보인다.
때문에 프로젝트가 커질수록, 쌓아온 테스트코드가 있는 쪽이 큰 효율과 안정성을 가진다.

시간의 단축(빠른 피드백)

큰 프로젝트일수록 테스트를 위해 실제 서버를 동작시키고,db에 접근하고,웹에서 실제 출력을 확인하는 것은 큰 비용과 시간을 필요로 한다.
테스트 코드를 이용하면 이보다 더 빠르고 간편하게,더 로우레벨의 값까지 확인할 수 있다.

수동테스트보다 확실함(자동검증)

실제로 프로그램을 돌려보며 결과를 확인하는 과정에서 사람인만큼 실수가 발생할 여지가 있다. 테스트 코드를 이용한다면 이를 보완할 수 있다.

테스트 코드가 문서의 역할을 할 수 있다.

테스트 코드는 그 자체로 협업 개발자에게 코드를 설명하는 역할을 할 수 있다. 어떤 입력값을 고려했는지에 대한 의도를 알릴 수 있다.

테스트코드 작성(java,spring boot)

junit이란?

java의 대표적인 testing framework,단위 테스팅 도구이다.
스프링 이니셜라이저를 이용한 경우 자동으로 의존성으로 등록이 된다.

테스트 코드 생성

class의 안쪽을 선택하고 ctrl+shift+t를 입력하면 test를 생성하는 옵션을 볼 수 있다.

classname과 생성할 method를 선택하고 OK를 누르면 Test 디렉토리 안에서 선택했던 class와 같은 위치에 테스트코드 클래스가 생성된다.

  • 메소드를 선택하지 않은 경우 기본 생성된 모습

좋은 단위 테스트의 속성(FIRST)

하지만 아무렇게나 테스트 코드를 작성한다고 해서 테스트가 의미있지는 않다. 예외가 숭숭 뚫린 테스트 코드, 산발적으로 다른 결과를 내는 테스트 코드, 코드의 케이스를 충분히 커버하지 못하는 테스트 코드는
시간낭비일 뿐만아니라 잘못된 확신을 심어주어 개발에 해가 된다.
때문에 좋은 단위 테스트 코드의 요건에 대해 인지해야 한다.

FIRST

다섯가지의 원칙으로 Fast,Isolated,Repeatable,Self-validating,
Timely의 앞글자를 따서 FIRST라 불리는 원칙이 있다.
이를 간과한 테스트 코드의 예시를 보자.

@SpringBootTest
class ArticleServiceTest {
    @Autowired
    private ArticleService articleService;
    @Autowired
    private ArticleRepository articleRepository;
    
    @Test
    void article_저장(){
        String testTitle="test update....";
        ArticleRequestDto testArticleDto=ArticleRequestDto.builder()
        						.title(testTitle).contents("testtest....123")
                                .contentsHtml("<p>testtest....123</p>")
                                .contentsMd("testtest....123").build();
      	Article article=new Article(testArticleDto);
    	Article saved=articleRepository.save(article);
        System.out.println(article.getTitle());
        System.out.println(articleService.findById(saved.getId()).getTitle());
   

    }

}

위의 테스트는 문제가 있다.

  • Fast
    단위 테스트는 가능한 빠르게 실행되어야 한다. 테스트 실행속도가 느려 테스트를 꺼리게되면 좋은 테스트가 아니다.
    -->위 코드의 @SpringBootTest는 모든 빈이 Ioc 컨테이너에 등록되어 테스트가 실행되므로 느려진다.

  • Independent
    테스트 코드를 작성하는 중에는 가장 신경써야 할 부분이다. 단위테스트는 다른 메소드, 이전의 테스트,객체의 상태 등에 의존해서는 안된다
    즉 테스트할 대상이 하나이어야 하며 제외한 다른 요건의 영향을 받지 않아야 한다.
    -->위 코드에서는 Articleservice를 테스트하면서 articleRepository에도 의존하기에 둘 중 어느것이 테스트 대상인지 모호하다. service가 테스트 대상이라면 articleRepository에 대한 의존성을 최소화해야 한다. 또한 이전에 같은 테스트를 수행하여 같은id의 article이 저장된 후라면 테스트는 실패한다. -이 때문에 Mock을 이용하거나 @transactional,@BeforeEach,@BeforeAll등의 어노테이션이 지원되기도 한다.

  • Repeatable
    단위 테스트는 반복 가능해야한다.
    --> 위 설명처럼 테스트 실행 횟수에 따라 다른 결과가 도출되어서는 안된다.

  • Self-validating
    단위 테스트는 자체검증이 가능해야 한다.
    --> 위에서는 개발자가 printIn으로
    출력된 artcle의 제목을 직접 보고 같은지를 판단하지만 이는 잘못되었다.
    Assert문 등에 의해 성공여부를 자체적으로 알 수 있어야 한다.

  • Timely
    단위테스트가 우선 작성되고 나중에 제품코드가 작성되어야 한다. 이는 TDD의 경우에 적용이 되는 원칙이다.

given-when-then 패턴

반드시 지켜야 할 원칙이라 할 수는 없지만 테스트 코드의 가독성 면에 도움을 줄 수 있다. 준비-실행-검증을 말한다. 테스트 코드를 준비(given)-실행(when)-검증(then)이 드러나게 작성한다.

커피의 가격,예상되는 할인가를 준비하고,
커피할인 메소드를 실행한 뒤,
assert를 통해 결과를 검증한다.

+REFERENCE
https://dzone.com/articles/writing-your-first-unit-tests
https://galid1.tistory.com/772
https://brunch.co.kr/@springboot/292

post-custom-banner

0개의 댓글