개발공부/이론 공부

[이론 공부] 테스트를 조금 더 많이 해보는건 어떨까?

장아장 2023. 6. 29. 18:23

프로젝트를 해보면서, 가장 중요하게 여겼던 것이 테스트였다. 

기능을 빠르게 만들어 바로 적용시키기보다, 테스트를 통해 모든 경우의 수를 고려해, 이에 따른 결과들을 미리 확인 할 수 있다는 장점이 있기 때문이다. 

 

여태까지는 생각 없이 테스트를 만들었다. 

  • 도메인 : Junit을 이용한 테스트
  • service(비즈니스 로직) : SpringBootTest를 이용한 테스트
  • controller : SpringBootTest를 이용한 테스트

이런 방식으로 단위테스트들을 만들었는데, 가장 큰 문제가 너무 무겁다는 것이다. 

 

해결하기 위해 Mockito를 공부하다가 단위테스트, 통합 테스트, 인수 테스트를 알게 되었다. 

당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다. 당신은 탈모빔에 맞았습니다.


단위 테스트

여행가면 날씨보기 뭣같은 이유
글쓴이 지금 이렇다.

단위 테스트는, 말 그대로 '단위' 단위로 테스트를 한다는 뜻이다!!!( 말 참 재밌네 이거ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ )

장난이고, 단위 테스트는 우리가 테스트해야 할 대상의 단위를 정하고, 이 단위를 기준으로 테스트를 하겠다는 뜻이다. 

보통은 클래스, 혹은 메서드 단위로 테스트를 하게 되는데, 필자 같은 경우에는 도메인은 클래스 단위로 테스트클래스를 만들고 메서드에 로직이 조금 들어가는 순간, 해당 메서드를 단위로 테스트클래스를 만든다. 

 

이렇게 하는 이유는, 나는 단위 테스트에서 성공과 실패를 모두 보기 때문이다. (나는!! 이다. 누군가는 통합도 성공과 실패를 할 수도, 단위에서도 성공만 볼 수도 있다)

 

예를 들어보자면, 

비밀번호를 바꾼다고 해보자. 

성공을 하려면, 그냥 내 비밀번호, 새 비밀번호, 새 비밀번호 재입력을 제대로 넣으면 된다. 

실패를 하려면?

  • 토큰이 없다(즉 로그인 후, 토큰을 받지 못한 상태다)
  • 내 비밀번호가 Member 객체에 저장되어있던 비밀번호와 다르다
  • 새 비밀번호와 새 비밀번호 재입력이 서로 다르다. 
  • 비밀 번호 3가지중 하나라도 입력을 받지 못했다. 

의 경우가 있다. 이러한 모든 경우를 고려해서 만드는 편이다.

이렇게 테스트 경우를 만들다보면 도메인 < 비즈니스 로직 < 컨트롤러 로직 순으로 실행 결과 경우의 수가 많아지는 경험을 했다. 

그래서 비즈니스, 컨트롤러는 테스트의 경우들을 다 나누었다. 

이런식으로 나뉘는 경우까지 가버렸다...클래스 하나의 테스트 중 '일부만' 가져왔다.

최근에는 단위 테스트를 위해 Mockito를 쓰고 있다. 

SpringBootTest는 실제 프로젝트 실행을 위한 컨텍스트, Configuration, Component등을 전부 로드하고 이후에 테스트를 실행했다. 

즉, 모든 클래스들을 확인하고 실제 프로젝틀 실행을 시킨 후 해당 부분만 보는 식이다. 

프로젝트 전체의 사이즈가 커지면 매우매우매우매우 비효율적이게 된다. 

이를 방지하기 위해 Mockito를 쓰기 시작했다. 

매우 가벼운 대신에, 귀찮다(!!!). 내가 테스트하려는 대상 클래스를 동작시키기 위한 모든 것들을 직접 세팅해주어야 한다. 

이에 대해서는 Mockito를 공부하면서 더 자세하게 작성한 후 주소를 달겠다. 

 


통합 테스트

아멘을 할까 마하반야를 외칠까 헤으응을 외칠까?

통합은 단위의 반대라고 생각하면 간단하다. 해당 동작을 함에 있어 묶이는 모오든 것들을 모아서

통합적으로 테스트한다고 생각하면 편하다. 

@SpringBootTest를 통해 테스트를 동작하게 한다(이래서 내 테스트가 겁나게 무거웠던건가 보다!!)

이렇게 하면, 실제 상황에서 동작하는 것과 같은 움직임을 보인다. 

하지만 왜때문에 에러가 났는지 찾아다녀야 하는 번거로움이 존재한다. 

또한 테스트하는 코드가 많아지며 신뢰성을 가지기 어렵다. 


인수테스트

단위 테스트도, 통합테스트도 테스트하려는 클래스의 시점까지만 시행을 한다는 점, 그리고 개발을 위해 하는 테스트라는 점이 있다. 

이와 반대로 인수테스트는 사용자 시점에서 요청을 보내고 응답을 받기까지, E2E(End 2 End) 과정을 테스트한다는 것, 그리고 개발이 아닌 프로젝트에 참여하는 비개발 직군의 사람들과 함께 토의하며 나오는 실제 프로젝트가 움직이는 시나리오를 짜고, 이에 대한 것을 검증한다는 것이다. 

 

여기서 다른 집단에서 받은 시나리오를 받아(인수) 테스트를 한다고 해서 인수테스트라고 한다. 

근데, '인수' 라고 하면 인수 병합( M&A ) 랑, 박인수(카트라이더 프로) 부터 생각이 났다. 

유튜브에서 봤다..카트 하는 실력이 끼깔나더라..

일단 인수테스트는 위에서 말한 end to end의 형식을 따른다. 즉, 누가 뭘 위해 무엇을 했다 가 명시되며, 시나리오가 어떻게 동작하는지만 생각하면 된다. 안에서 코드가 어떤지는 생각하지 않는다. 

인수테스트에서는, 시나리오에 짜여진 대로만을 요구하기 때문에, 개인적으론 단위와 통합과는 다른 접근이라고 느낀다. 

이 때에는 RestAssured를 이용한다. 

이런 식으로 given / when / then을 따르며, 이 때 

given은 요청의 데이터가 무엇인지, when에서는 어떤 url인지, http method가 무엇인지, then에서는 어떤 결과가 나오는지를 확인한다. 

클라이언트가 어떤 데이터를 가지고 요청을 할 때 무슨 url이 무슨 결과를 도출할지를 검증하는 것이다. 


각 테스트는 사용 용도도 다르고, 이를 통해 우리가 얻고자 하는 바도 다르다고 생각한다. 

무엇을 먼저 할지는 사실 모호하다고 느낀다. 

 

만약 찐또배기 TDD를 하겠다면, 인수 테스트가 만들어지고, 이를 위한 클래스 별로 통합테스트를 만들고, 그 통합테스트를 위한 단위테스트를 TDD로 만들 것 같기도 하다. 

 

그런데, 테스트 자체는 익히는 점이 어렵진 않았다. 

아까 말했듯이, 하나의 로직에 대해서 하나 이상의 테스트가 생기게 된다. (단위는 n개, 통합이나 인수는 1개정도?)

프로젝트를 하면서 계속 테스트를 쓰다보니 테스트가 익숙해지긴 한다. 

사실 현재 시점에서는 오히려 컨벤션을 지키며 개발을 하는 점이 더 스트레스같다. 

(이건 이렇게..저건 저렇게... 뭐랄까 지식을 고치는 것은 어렵지 않은데 컨벤션은 습관을 고치는 느낌...)

 

그래도 다들 성공하길 바란다. 

 

 

그럼...twenty thousand...🔥