とりあえずコードだけ。
money.py
#!/usr/bin/env python # coding: utf-8 """テスト駆動開発入門 14章 変化 """ class Expression(object): def reduce(self, bank, currency_to): raise NotImplementedError class Money(Expression): def __init__(self, amount, currency): self._amount = amount self._currency = currency def __mul__(self, multiplier): return Money(self._amount * multiplier, self._currency) @staticmethod def dollar(amount): return Money(amount, "USD") @staticmethod def franc(amount): return Money(amount, "CHF") def currency(self): return self._currency def reduce(self, bank, currency_to): rate = bank.rate(self._currency, currency_to) return Money(self._amount/rate, currency_to) def __eq__(self, other): return self._amount == other._amount and \ self.currency() == other.currency() def __str__(self): """デバッグ用出力文字列 """ return str(self._amount) + " " + str(self._currency) __unicode__ = __str__ __repr__ = __str__ def __add__(self, addend): return Sum(self, addend) class Bank(object): def __init__(self): self.rates = dict() def reduce(self, source, currency_to): return source.reduce(self, currency_to) def rate(self, currency_from, currency_to): if currency_from == currency_to: return 1 return self.rates[(currency_from, currency_to)] def add_rate(self, currency_from, currency_to, rate): self.rates[(currency_from, currency_to)] = rate # Hashtableをdictionaryで実装 class Sum(Expression): def __init__(self, augend, addend): self.augend = augend self.addend = addend def reduce(self, bank, currency_to): amount = self.augend._amount + self.addend._amount return Money(amount, currency_to)
money_test.py
#!/usr/bin/env python # coding: utf-8 """テスト駆動開発入門 14章 変化 """ import unittest from money import * class TestMoney(unittest.TestCase): """moneyモジュールのテスト """ def testMultiplication(self): """かけ算のテスト """ five = Money.dollar(5) self.assertEqual(Money.dollar(10), five * 2) self.assertEqual(Money.dollar(15), five * 3) def testFrancMultiplication(self): """Francクラスのかけ算のテスト """ five = Money.franc(5) self.assertEqual(Money.franc(10), five * 2) self.assertEqual(Money.franc(15), five * 3) def testEuality(self): """同値テスト """ self.assert_( Money.dollar(5) == Money.dollar(5) ) self.assert_(not Money.dollar(5) == Money.dollar(6) ) self.assert_(not Money.franc(5) == Money.dollar(5) ) def testCurrency(self): """通貨単位のテスト """ self.assertEqual("USD", Money.dollar(1).currency() ) self.assertEqual("CHF", Money.franc(1).currency() ) def testSimpleAddition(self): """足し算のテスト """ five = Money.dollar(5) sum = five + five self.assert_(Money.dollar(10), sum) bank = Bank() reduced = bank.reduce(sum, "USD") self.assertEqual(Money.dollar(10), reduced) def testPlusReturnsSum(self): five = Money.dollar(5) result = five + five sum = result self.assertEqual(five, sum.addend) self.assertEqual(five, sum.augend) def testReduceSum(self): sum = Sum(Money.dollar(3), Money.dollar(4) ) bank = Bank() result = bank.reduce(sum, "USD") self.assertEqual(Money.dollar(7), result) def testReduceMoney(self): bank = Bank() result = bank.reduce(Money.dollar(1), "USD") self.assertEqual(Money.dollar(1), result) def testReduceMoneyDifferentCurrency(self): bank = Bank() bank.add_rate("CHF", "USD", 2) result = bank.reduce(Money.franc(2), "USD") self.assertEqual(Money.dollar(1), result) def testIdentityRate(self): self.assertEqual(1, Bank().rate("USD", "USD") ) if __name__ == "__main__": unittest.main()