테스트 주도 개발 | 1장 다중 통화를 지원하는 Money 객체

날짜
May 22, 2024
태그
TDD
python
설명
기본적인 테스트 성공시키기
Github에서 예제 코드를 확인할 수 있어요.
 
기존 보고서를 보자
종목
가격
합계
IBM
1000
25
25000
GE
400
100
40000
합계
65000
 
새로운 보고서는 다중 통화를 지원하는 보고서를 만드려면 통화 단위를 추가해야 한다.
종목
가격
합계
IBM
1000
25USD
25000USD
Novartis
400
150CHF
60000CHF
합계
65000USD
 
환율도 명시해야 한다.
기준
변환
환율
CHF
USD
1.5
 

TODO LIST

$5 + 10CHF = $10(환율이 2:1)일 경우
$5 X 2 = $10
 
새로운 보고서를 생성하려면 어떤 기능들이 있어야 할까? 즉, 어떤 테스트가 있어야(모두 통과할 경우) 보고서가 완성됐다는 것을 확신할 수 있을까?
  • 통화가 다른 두 금액을 더해서 주어진 환율에 맞게 변한 금액을 결과로 얻을 수 있어야 한다.
  • 어떤 금액(주가)을 어떤 수(주식의 수)에 곱한 금액을 결과로 얻을 수 있어야 한다.
 
우선 어떤 테스트가 필요할까? 할 일 목록을 보니 첫번째 보다는 두번째가 더 간단해 보인다. 테스트를 작성할 땐 완벽한 인터페이스에 대해 상상해보는 것이 좋다. 우리는 지금 외부에서 어떤 식으로 보일지에 대한 테스트 코드를 적는 것이다.
 

 

테스트 구성하기

from django.test import TestCase class TestDollar(TestCase): def setUp(self): pass def TearDown(self): pass def test_multiplication(self): five = Dollar(5) five.times(2) self.assertEqual(10, five.amount)
moneys 앱의 테스트 구성
 
>>> python moneyapp/manage.py test moneys Creating test database for alias 'default'... System check identified no issues (0 silenced). E ====================================================================== ERROR: test_multiplication (moneys.tests.TestDollar) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/googie/Desktop/TDD-example/moneyapp/moneys/tests.py", line 12, in test_multiplication five = Dollar(5) NameError: name 'Dollar' is not defined ---------------------------------------------------------------------- Ran 1 test in 0.000s FAILED (errors=1) Destroying test database for alias 'default'...
테스트를 돌리면 당연히 에러가 발생한다.
  • Dollar 클래스 없음
  • 생성자가 없음
  • times() 메서드가 없음
  • amount 필드가 없음
 
하나씩 TODO를 지워가보자. Dollar 클래스를 정의하면 하나를 없앨 수 있다.
class Dollar: def __init__(self, amount: int): self.amount = amount def times(self, multiplier: int): pass
models.py에 Dollar를 정의했다.
 
>>> python moneyapp/manage.py test moneys Creating test database for alias 'default'... System check identified no issues (0 silenced). F ====================================================================== FAIL: test_multiplication (moneys.tests.TestDollar) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/googie/Desktop/TDD-example/moneyapp/moneys/tests.py", line 15, in test_multiplication self.assertEqual(10, five.amount) AssertionError: 10 != 5 ---------------------------------------------------------------------- Ran 1 test in 0.000s FAILED (failures=1) Destroying test database for alias 'default'...
에러가 아닌 실패한 테스트를 확인했다.
 
테스트를 성공시켜 보자.
class Dollar: def __init__(self, amount: int): self.amount = 10
>>> python moneyapp/manage.py test moneys Creating test database for alias 'default'... System check identified no issues (0 silenced). . ---------------------------------------------------------------------- Ran 1 test in 0.000s OK Destroying test database for alias 'default'...
테스트가 성공했다.
 
이제 상수가 아닌 변수로 변경해서 점진적으로 일반화를 시켜보자.
class Dollar: def __init__(self, amount: int): self.amount = amount def times(self, multiplier: int): self.amount *= multiplier
times 함수의 내부를 정의했다.
 

테스트의 주기

  1. 작은 테스트를 하나 추가한다.
  1. 모든 테스트를 실행해서 테스트가 실패하는 것을 확인한다.
  1. 조금 수정한다.
  1. 모든 테스트를 실행해서 테스트가 성공하는 것을 확인한다.
  1. 중복을 제거하기 위해 리팩터링을 한다.
 

TODO LIST

$5 + 10CHF = $10(환율이 2:1)일 경우
$5 X 2 = $10
amount를 private 만들기
Dollar 부작용
Money 반올림
 
이제 첫번째 테스트에 완료를 표시할 수 있게 됐다. 우리는 다음 작업을 해냈다.
  • 우리가 알고 있는 작업해야 할 테스트 목록을 만들었다.
  • 오퍼레이션이 외부에서 어떻게 보이길 원하는지 말해주는 이야기를 코드로 표현했다.
  • 스텁(테스트에 필요한 호출에 대해 미리 준비된 답을 제공하는 객체) 구현을 통해 테스트를 실행했다.
  • 끔찍한 방법으로라도 테스트를 통과시켰다.
  • 상수를 변수로 변경하여 점진적으로 일반화했다.
 

댓글

guest