클라이언트/ 서버/ 엔지니어 " 게임 개발자"를 향한 매일의 공부일지

나의 첫 테스트 코드 2 - 유닛 테스트의 조건 본문

웹 · 앱 개발/디버깅

나의 첫 테스트 코드 2 - 유닛 테스트의 조건

huenuri 2024. 7. 30. 11:09

이제 테스트 코드의 두번째와 세번째 단원만 학습하면 3주차 학습도 마치게 된다. 요즘 듣는 수업들은 이론 수업들이 전보다 많아지고 어렵기에 정리를 하는 것도 쉽지 않다.
내가 이해를 해야 정리할 수 있는데 한번 들어서는 잘 이해되지 않기도 한다. 어떤 때는 내가 분명 기록했는데 다시 읽어보면 무슨 소리인지 잘 모르겠는 것도 있었다.

아무튼 배우는 것만큼 복습도 정말 중요하다. 그럼 바로 학습에 들어가보자!


 

이론 3 - 유닛 테스트의 조건

 

3번과 4번 조건이 조금 특이하다. 작으면서 넓어야 한다는 뜻은 무엇일까?

 

 

1. 읽기 쉽다

 

테스트의 내용을 쉽게 이해할 수 있어야 한다. 즉 함수 안의 내용이 테스트를 잘 드러내고 있어야 한다.
초보자들이 잘하는 실수 중에 하나는 테스트 이름을 test1이라는 식으로 매기는 것이다. 하지만 두번째 예시에서처럼 함수 이름을 작성하면 어떤 함수인지 구별할 수 있고, level이라는 매개변수를 받고 있다는 것도 알 수 있다. 일반적으로 함수 이름을 간결하게 적는 것이 미덕이지만, 테스트 코드에서는 그렇지 않다. 어떤 코드인지 함수 이름에 온전히 담고 있어야 한다.

 

 

 

 

2. 독립적이다

 

2주차 미션에서 홈 스타트 온도계 만들기에서 heater라는 클래스를 만들었다. 어렵게 문제를 풀어보길 잘했다.
이 함수는 control_heater를 리턴하는 코드이다. 테스트 코드 이름을 보면 이런 부분이 잘 나타나있다. 히터를 컨트롤하는 테스트 코드를 만들텐데 그 상황은 추울 때이다. 즉, 현재 온도보다 희망자가 설정한 온도보다 낮을 때(추울 때) 컨트롤 히터가 잘 작동하는지를 알아보는 것이다.

마지막 코드는 함수가 실행되고 있을 때, 히터가 켜져있는지 확인하는 코드이다.

 

 

 

 

두번째 control_heater 함수는 더울 때 작동이 되는 함수이다. 현재 온도가 희망 온도보다 높을 때 작동이 된다.

 

 

 

 

하지만 누군가가 cold와 hot의 순서를 바꾸었더니 fail 하고 있다. 테스트를 통과하지 않고 assert문에서 에러가 났다는 것이다. 예를 들어서 선생님이 시험 문제를 채점하는데 1번과 2번 문제의 채점 순서를 바꾸었을 때, 결과가 다르다는 것과 비슷한 말이다.

왜 이런 결과가 나올까? 우리는 하나의 함수를 설정하기 위해 heater라는 변수를 만들었다. 그런데 첫번째 함수를 실행하면 control 히터의 온도가 바뀌어있다. 두번째 함수에서 그 히터를 그대로 사용하고 있다.
언제나 히터를 켜놓도록 만들어놓았다면 cold를 실행한 후에 히터는 언제나 켜져있을 것이다. 이 켜져있는 히터를 가지고 두번째 함수를 실행하게 된다.

 

 

 

 

 

주의 사항

어떤 클래스를 이용해 객체를 만들 때 항상 새로운 히터 변수를 만들어야 한다는 것이다. 테스트 코드 안쪽에 생성한다. 사용한 후에는 그 히터를 절대로 다시 사용해서는 안된다. 그런 다음에 두번째 테스트 코드를 진행해야 한다.

독립적이다 : 하나의 테스트 코드 함수가 다른 테스트 코드 함수에 영향을 받아서는 안된다. 테스트 코드간의 공유가 존재해서는 안됨

 

 

 

 

 

3. 충분히 작다

테스트 히터를 생성하고 뭔가를 수행한다. 히터가 켜져있는지 테스트하고, 지금의 온도가 몇 도인지 읽어주는 기능이 잘 작동하는지도 확인하는 함수이다. 2가지 일을 테스트 코드 안에서 하고 있다.
둘 중의 하나라도 잘못되면 assert문은 둘 중 하나가 실패할 것이다. 그렇다면 내가 어느 부분을 고쳐야 하는지 알 수 있다.

하지만 이 테스트 코드 상에서는 어느 부분이 틀렸는지 확인할 수 없다. 이런 테스트 코드는 좋지 않고, 다음의 내용처럼 두 개의 함수를 분리하는 것이 좋다.

 

 

 

 

 

첫번째 함수에서는 켜져 있는지, 두번째 함수에서는 제대로 읽고 있는지 확인한다. 이렇게 각각의 함수가 맡고 있는 영역이 충분히 작아야 한다.

 

 

 

 

4. 충분히 넓다

영어로는 edge case라고 한다.

 

 

 

 

 

 

예시 1

 

조금 전에 우리는 hot과 cold라는 2가지 control 함수를 살펴보았다. 하지만 이 두 가지 상태만을 대변하고 있지 않다. 어떤 경우가 있을까?

현재 온도와 설정 온도가 같은 경우도 존재한다. 이 경우에는 어떤 코드가 들어가야 할까?

 

 

 

 

 

현재 온도를 측정할 수 없는 극단적인 상황도 발생할 수 있다. 두 온도를 비교할 수 없는 상황도 존재한다. 테스트 코드를 작성한다는 것은 설계이다. 그러므로 설계의 빈틈이 없이 만들어 주는 것이 좋은 테스트 코드의 역할이다.

 

 

 

예시 2

 

빈 문자열이 들어오는 경우에는 어떻게 해야 하는가?

 

 

 

 

 

특수 기호로 이루어진 경우도 있는데, 이것은 회문일까? 이러한 부분을 테스트 코드로 다루어지지 않으면 개발자의 설계는 비어있는 것과 같다.

충분히 넓다 : 각각의 테스트는 작아야 하지만, 이 테스트들이 이루고 있는 전체 영역이 실제로 발생할 수 있는 다양한 돌발상황들을 모두 커버할 수 있어야 한다

 

이 두 가지는 충분히 공존할 수 있는 영역인 것이다.


 

실습 2 - 스마트 홈 테스트

이론 수업이 굉장히 길었지만 정말 중요한 내용을 설명하고 있었다. 이제 실습 문제를 통해 어떻게 테스트 코드를 작성하는 것이 좋은지 알아보기로 하자.

 

문제 설명

 

 

 

현재 온도가 희망 온도보다 낮으면 히터를 히터를 켜는데 같을 때는 어떻게 설정해야 할지 생각해야 한다. 먼저 smart_home.py에서 히터가 어떻게 생겼는지 살펴본다.

 

 

is_turned_on이라는 속성이 있고, 방 안의 온도를 나타내는 current_temperature, 희망 온도를 나타내는 prererred_temperature 속성도 있다.

 

 

 

히터라는 객체를 메인에서 생성했다. 이것은 테스트 코드의 독립성 때문이다. 히터를 세팅하고 control 히터를 작동시킨다. 그런 다음 히터가 자동으로 켜지는지 확인한다.
만약에 true라면 왼쪽이 true고 오른쪽이 false이므로 assert문은 false가 된다. 그리고 희망 온도와 현재 온도를 거꾸로 쓰면 제대로 작동하지 않는다.

 

 

 

 

스스로 풀어보기

이제 혼자서 문제를 풀어보는 시간이다.

 

 

assert문에서 현재 온도가 희망 온도보다 낮을 때 히터가 자동으로 켜진다고 했으니까 온도가 같을 때는 꺼져야 한다. 그러니까 assert는 false가 되어야 하는 것이다.

 

 

하지만 코드가 틀렸다. control_heater를 설정하지 않았다.

 

 

 

 

이제 잘 채점이 되었다.


 

두번째 단원 학습을 마치고

분량이 많아서 여기서 끊고 다음 포스트에서 파이썬의 유닛에 대해서 학습해보려고 한다. 테스트 코드를 어떻게 작성해야 하는지 충분히 배울 수 있는 시간이었다.
이것은 테스트 코드뿐 아니라 함수를 만들고 코드를 작성할 때도 해당되는 것 같다. 에러인 조건이 생기지 않는지 잘 살펴보고 모든 가능성을 다 확인해보는 것.. 그것이 개발자에게 정말 중요한 능력임을 알게 되었다.

그렇게 프로그램을 짜야 사용자에게 버그 없는 편리한 기술을 선보일 수 있기 때문이다. 일단 출시가 되면 버그를 잡는 건 참 어려운 것 같다. 그전에 모든 가능성을 생각해보며 최대한 이 오류를 잡기 위해 노력해야 할 것이다.