Pythonでテスト駆動開発
testができる環境を作ろう
$ brew install pyenv
$ pipx install poetry
poetryでproject作成
$ poetry init
ディレクトリ構成を整える
$ tree -L 3
code:zsh
.
├── Makefile
├── README.md
├── pyproject.toml
├── src
├── tests
└── todo.md
何度もpoetry runを入力するのは面倒なので、makefileを作っておく
今回はunittestを使ってtestを書いていくので、このコマンド
code:makefile
test:
poetry run python -m unittest discover -s ./tests -p "test_*.py" -v
$ make testを実行すれば、testが実行される
0. todoリストに気になることを全部書く
1. 小さいテストを1つ書く
2. 全てのテストを実行し、1つ失敗することを確認する
3. 小さな変更を行う
4. 再びテストを実行し、すべて成功することを確認する
5. リファクタリングを行い、重複を除去する
小さいテストを1つ書こう
todoリストはこんな感じ
code:todo.md
- [] $5 + 10CHF = $20(レートが2:1の場合)
- [] $5 * 2 = $10
cosense表記だとこうなる
sample
$5 + 10CHF = $20(レートが2:1の場合)
$5 * 2 = $10
早速testを書く
code:tests/test_money.py
import unittest
from src.dollar import Dollar
class TestMoney(unittest.TestCase):
def test_multiplication(self):
five = Dollar(5)
five.times(2)
self.assertEqual(10, five.amount)
testを実行してみる
$ make test
code:result
ImportError: cannot import name 'Dollar' from 'src.dollar'
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
srcコードを書く
まず、成功させたいのでベタ書きにする
(そもそもこれを書くまでの思考がスキップされてそうなのでちゃんと言語化したい)
code:src/dollar.py
from dataclasses import dataclass
@dataclass
class Dollar:
amount: int
def times(self, multiplier: int) -> int:
self.amount = 10
testを実行してみる
code:zshr
$ make test
poetry run python -m unittest discover -s ./tests -p "test_*.py" -v
test_multiplication (test_money.TestMoney.test_multiplication) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
重複を消していこう
10を分解すると5 * 2
code:src/dollar.py
from dataclasses import dataclass
@dataclass
class Dollar:
amount: int
def times(self, multiplier: int) -> int:
self.amount = 5 * 2
$ make testで成功を確認
5は何かというとコンストラクタに渡された引数なので、置換しよう
code:src/dollar.py
from dataclasses import dataclass
@dataclass
class Dollar:
amount: int
def times(self, multiplier: int) -> int:
self.amount = self.amount * 2
$ make testで成功を確認
2は何かというと、mulitplierだから置換しよう
code:src/dollar.py
from dataclasses import dataclass
@dataclass
class Dollar:
amount: int
def times(self, multiplier: int) -> int:
self.amount = self.amount * multiplier
$ make testで成功を確認
重複を少しでも減らすために、*=演算子に変えよう
code:src/dollar.py
from dataclasses import dataclass
@dataclass
class Dollar:
amount: int
def times(self, multiplier: int) -> int:
self.amount *= multiplier