Rlog

어떤 것이 좋은 테스트 코드인가? 본문

Test

어떤 것이 좋은 테스트 코드인가?

dev_roach 2021. 11. 19. 09:59
728x90

프로그래밍을 계속 해오고 테스트코드를 작성하면서 내 일생을 관통할 주제 중 하나인 것 같다.

오늘은 그래서 Effective Unit Testing 을 읽으며 느낀 생각들을 정리해보려고 한다.

 

무엇이 좋은 테스트인가?

좋은 테스트 코드에는 아래와 같이 공통적인 다섯가지 요소들이 있다.

1.  테스트 코드의 가독성과 유지 보수성

우리가 현업에서 코드를 작성하다보면 흔히 불리우는 'Legacy' 로 구성된 시스템에 부딪힌다.

레거시 코드를 읽다보면 코드를 이해하는데만 오랜 시간을 쓰게 된다.

그래서 우리는 레거시 코드를 더 읽기 좋게 바꾸기 위해 리팩토링이란 것을 진행하고는 한다.

테스트 코드 또한 코드로 이루어져 있기에 가독성이 나쁘다면 'Legacy Code' 가 된다.

 

Legacy Code 를 만나보지 못한 분들을 위해 간단하게 왜 리팩토링이나 테스팅의 대상이 되는지를 설명해드리면

레거시 코드는 읽기도 힘들고, 내가 코드를 추가 했을때

어떤 사이드 이펙트를 발생시키는지도 알기가 힘들다.

이는 개발자에게는 공포의 대상이다. 

내가 추가한 코드가 어떤 영향을 끼치고 있을지 정확히 예측 불가능 하다는 것.

 

그래서 리팩토링을 하기도 무섭고, 반드시 테스팅을 붙인 뒤 리팩토링을 해야 하는데

이 또한 큰 작업이기도 하고, 제대로 테스트를 하고 있는지도 알기가 어렵다.

이러한 Legacy Code 의 두려움은 계속해서 개발자에게 Legacy  Code 를 추가할 수 밖에 없게 만든다.

Legacy 를 양산하지 않기 위해서는 어떤 개발자가 이곳에 오더라도 두려움을 느끼지 않도록 해주어야 한다.

 

그 두려움을 없애는 방법중 하나가 테스트 코드이고, 이 또한 코드로서 유지보수 되어야 할 대상이다. 

따라서 테스트 코드의 코드 퀄리티를 높게 가져가야 하는 이유 중 하나가 이 것이다.

2. 구조화가 잘 되어 있다면 이해하기 쉽다.

책에서는 필자가 JSP 페이지의 크기가 너무 커서 자바 바이트 코드의 범위를 넘어서서 

텍스트 편집기가 죽어버린 일도 있다고 했다.

하지만 더 큰 문제는 내가 어디에 어떤 코드를 추가해야 하는지 알기 힘들다는 경험이다.

 

내 경험을 살려 얘기를 해보면

회사에 리액트 페이지 중 하나가 엄청난 레거시의 유산으로 3600 줄에 육박하는 자바스크립트 코드가 있다.

이런 페이지에 들어가게 되면 어디에 어떤 코드를 추가해야 되는지 알기가 어렵다.

 

즉 1번 에서 말했던 내용과 같이 내가 코드를 작성하는데 두려움을 느끼는 것이다.

 

그래서 우리는 이를 Flux Pattern 구조로 이를 분리해내기 시작했다.

팀 내에서 Front-End 를 잘하는 개발자들이 이를 분리해내기 시작했고, 이 코드를 이해하기 위해

Flux Pattern 구조의 라이브러리를 공부했던 경험이 있다.

그래서 3600 줄의 코드가 여러 함수형 파일로 분리되었고

내가 어떤 구조파일에 들어가서 코드를 수정해야 하는지를 명확히 알 수 있게 되었다.

 

여기서 만약 저런 정형화된 구조가 아니라, 자신의 생각대로 구조를 짰다고 생각해보자.

이렇게 된다면 코드가 아무리 스플릿팅이 됬다고 하더라도

다른 팀원은 이를 이해하는데 엄청난 어려움을 겪을 것이다. 

즉 코드를 쪼개더라도 다른 사람이 느끼기에는 뭉텅이로 있던 코드랑 별 다를게 없다는 것 이다.

이것이 좋은 구조로 코드를 작성해야 하는 이유이다.

 

테스트 코드 또한 비슷하다.

만약 하나의 테스트가 작동하는데 30분이 걸리고 이 테스트 코드에서 문제가 발생했다고 해보자.

과연 문제를 쉽게 찾을 수 있을까?

아마도 쉽게 찾지 못할 것이다.

만약 찾아서 고친다고 해도 잘 고쳤는지 확인(피드백) 을 받기 위해서는 또 다시 30분이라는 시간이 걸린다.

 

즉, 테스트 코드 또한 비슷하다. 

한 가지 기능에 충실한 테스트가 이루어져야 하며, 어느 함수 혹은 클래스를 테스트하는 지 정확해야 한다.

3. 엉뚱한걸 검사하는 건 좋지 않다.

가끔 테스트 코드의 이름만 보고 신뢰를 얻어 테스트가 통과했구나 라고 생각할때가 있다.

한번 아래와 같은 코드를 보자.

public class TestBMap {
	@Test
    public void mask() {
    	Bmap bmap = new Bmap();
        bmap.addParameter(NAME);
        bmap.addParameter(DAYS, 0);
        bmap.addParameter(HOURES, 23);
        assertTrue(bmap.validate());
    }
}

위와 같은 코드를 보면 어떤 생각이 드는가?

 

mask 라는 것이 Bmap 과의 어떤 연관관계인지는 알수 없지만

테스트 코드의 내용으로 봤을때 단순히 Bmap 에 들어오는 Parameter 들이 유효한지만 검사하고 있다.

 

심지어 정상적인 입력값이 들어오고,

Bitmap 으로 Masking 을 하는 과정이 실패해도, 이 테스트는 통과할 것 이다.

masking 을 테스트하고 있지는 않으니까.

 

테스트 코드의 Naming 에 맞게 테스트를 해야 하는 이유이다.

엉뚱한 걸 테스트하게 되면 누군가 큰 시간을 낭비하게 될 수도 있다.

4. 독립적인 테스트는 혼자서도 잘 실행된다.

이 내용은 테스트를 작성해봤거나 조금이라도 공부해봤다면 들어봤을 거라고 생각한다.

 

만약 우리가 A TEST 를 실행시키는데 아래와 같이 선행되는 작업이 있다고 해보자.

 

1. A TEST 를 실행시키는 시간은 반드시 대한민국 AM 9:00 에만 통과할 수 있다.

 

만약 AM 8:00 에 돌렸다면 A TEST 는 유효한가?

그렇다면 우리는 AM 9:00 에만 피드백을 들을 수 있는 것인가?

 

이런 고민들은 '우리가 제어 할 수 없는 수단' 에 측한다.

하지만 개발자는 이러한 예측 불가능한 수단을 제어하고 싶어할 것이다.

이런 테스트를 개선하는 방법에 대해서 블로그에 적은 글이 있는데 궁금하다면 읽어보길 바란다.

https://devroach.tistory.com/35?category=1031971

 

테스트를 어떻게 해야하는가?

개요 최근 어떤 테스트가 좋은 테스트인지? 무엇을 테스트 해야 하는건지에 대한 의문점이 생겼다. 그래서 springcamp.io 에서 발표한 용근님의 발표내용을 정리해보려고 한다. https://ww

devroach.tistory.com

한가지로 개선할 수 있는 방법도 존재하지만,

결국 이런 예측 불가능한 테스트를 쉽게 테스트 할 수 있는 구조로 코드를 작성하는 것 또한 중요하다.

 

그리고 테스트 코드를 작성할때 중요한 점은 

글 소제목과 같이 절대 다른 테스트에 의존해서는 안된다는 점 이다.

만약 다른 테스트에 의존하게 된다면 아래와 같은 조건이 생길 것 이다.

 

1. A -> B 순서로 이루어져야만 B 테스트는 테스트를 통과할 수 있다.

 

그렇담 B 를 혼자 돌리게 된다면 틀린 테스트가 되는건가?

이건 잘 짜여진 테스트가 아니다.

즉, 테스트 간의 Dependency 를 없애야 한다.

5. 믿음직한 테스트여야 기댈 수 있다.

위의 내용이 합쳐진 주제라고 볼 수 있다.

필자의 예시로는 일 하는데 한가지 테스트 코드를 5번 돌리는 동료를 본 적이 있다고 한다.

그 테스트는 어떨땐 통과하고, 어떨 땐 통과하지 않았는데 

그 이유는 위에서 설명했듯 난수, 시간을 이용한 테스트였기 때문인데,

 

즉 우리가 제어할 수 없는 불가능한 수단에 기대어 테스트를 했기 때문이다.

현대 테스트 프레임워크틀은 이를 제어하기 위해 Mocking 등 여러가지 수단을 제공한다.

 

이런 테스트 프레임워크를 이용해서 좋은 테스트 코드를 작성하길 바란다.

'Test' 카테고리의 다른 글

[TEST] When 에서 하나 이상의 메소드 실행 피하기  (1) 2021.12.17
테스트 더블의 종류  (0) 2021.11.22
테스트 더블  (0) 2021.11.19
테스트를 어떻게 해야하는가?  (0) 2021.10.27