Die Beispiele in ** Teil I "Multilaterale Währung" ** des Buches "Test Driven Development" basieren also auf JAVA Um mein Verständnis zu vertiefen, habe ich die gleiche Praxis in Python versucht.
Der Code der testgetriebenen Entwicklungspraxis ist übrigens im folgenden Github gespeichert. https://github.com/ttsubo/study_of_test_driven_development/tree/master/python
Das im Buch "Testgetriebene Entwicklung" empfohlene Verfahren für die testgetriebene Entwicklung lautet wie folgt.
Auch in dieser Praxis werden wir dieses Verfahren so weit wie möglich befolgen.
Die folgenden zwei Anforderungen sollten realisiert werden.
Multiplizieren Sie zunächst den Betrag (Betrag pro Währungseinheit) mit einem numerischen Wert (Anzahl der Währungseinheiten), um den Betrag zu erhalten. Wir streben einen Mechanismus namens `an. Insbesondere werden wir mit der Codierung fortfahren, so dass "$ 5 * 2 = $ 10" gilt.
Erstellen Sie einen Test, der bestätigt, dass "$ 5 * 2 = $ 10" gilt.
tests/test_money.py
from testtools import TestCase
from example.dollar import Dollar
class MoneyTest(TestCase):
def testMultiplication(self):
five = Dollar(5)
five.times(2)
self.assertEqual(10, five.amount)
Stellen Sie den Code bereit, der nur die Klasse "Dollar" lädt.
example/dollar.py
class Dollar:
pass
Der Test schlägt fehl, weil die Dollar-Klasse nicht objektiviert werden kann.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testMultiplication FAILED [100%]
================================== FAILURES ===================================
___________________________ MoneyTest.testMultiplication ______________________
NOTE: Incompatible Exception Representation, displaying natively:
testtools.testresult.real._StringException: Traceback (most recent call last):
File "/Users/ttsubo/source/study_of_test_driven_development/tests/test_money.py", line 6, in testMultiplication
five = Dollar(5)
TypeError: Dollar() takes no arguments
Definieren Sie einen Konstruktor, damit Sie die Klasse "Dollar" objektivieren können.
example/dollar.py
class Dollar:
def __init__(self, amount):
self.amount = amount
Der Test schlägt fehl, weil für die "Dollar" -Klasse keine "Times" -Methode definiert ist.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testMultiplication FAILED [100%]
================================== FAILURES ===================================
___________________________ MoneyTest.testMultiplication ______________________
NOTE: Incompatible Exception Representation, displaying natively:
testtools.testresult.real._StringException: Traceback (most recent call last):
File "/Users/ttsubo/source/study_of_test_driven_development/tests/test_money.py", line 7, in testMultiplication
five.times(2)
AttributeError: 'Dollar' object has no attribute 'times'
`Multiplizieren Sie den Betrag mit einer Zahl, um den Betrag zu erhalten. Die "times" -Methode definiert es so, dass es sein kann.
example/dollar.py
class Dollar:
def __init__(self, amount):
self.amount = amount
def times(self, multiplier):
self.amount *= multiplier
Schließlich ist der Test erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
In Kapitel 1 erhalten Sie den Betrag, indem Sie den Betrag (Betrag pro Währungseinheit) mit einer Zahl (Anzahl der Währungseinheiten) multiplizieren. Als Mechanismus namens habe ich versucht, das notwendige Minimum zu implementieren. Außerdem wird hier der Betrag (Betrag pro Währungseinheit) mit einem numerischen Wert (Anzahl der Währungseinheiten) multipliziert, um den Betrag zu erhalten. Wir werden den Mechanismus namens
so erweitern, dass er viele Male aufgerufen werden kann.
Nachdem Sie bestätigt haben, dass "$ 5 * 2 = $ 10" gilt, erstellen Sie einen Test, der auch "$ 5 * 3 = $ 15" enthält. Es wird angenommen, dass die "Dollar" -Klasse einmal zu einem Objekt gemacht wird und dann der Multiplikationswert zum Testen auf verschiedene Arten geändert wird.
tests/test_money.py
from testtools import TestCase
from example.dollar import Dollar
class MoneyTest(TestCase):
def testMultiplication(self):
five = Dollar(5)
product = five.times(2)
self.assertEqual(10, product.amount)
product = five.times(3)
self.assertEqual(15, product.amount)
Der Test schlägt fehl, da wir die Logik zum Abrufen des Ausführungsergebnisses der "times" -Methode des "Dollar" -Objekts noch nicht implementiert haben.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testMultiplication FAILED [100%]
================================== FAILURES ===================================
___________________________ MoneyTest.testMultiplication ______________________
NOTE: Incompatible Exception Representation, displaying natively:
testtools.testresult.real._StringException: Traceback (most recent call last):
File "/Users/ttsubo/source/study_of_test_driven_development/python/tests/test_money.py", line 8, in testMultiplication
self.assertEqual(10, product.amount)
AttributeError: 'NoneType' object has no attribute 'amount'
Implementieren Sie die Logik, um das Ausführungsergebnis der "times" -Methode des "Dollar" -Objekts zu erhalten.
--Erstellen Sie ein neues "Dollar" -Objekt, wenn Sie die "times" -Methode des "Dollar" -Objekts aufrufen
example/dollar.py
class Dollar:
def __init__(self, amount):
self.amount = amount
def times(self, multiplier):
return Dollar(self.amount * multiplier)
Der Test ist jetzt erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
In Kapitel 2 erhalten Sie den Betrag, indem Sie den Betrag (Betrag pro Währungseinheit) mit der Anzahl (Anzahl der Währungseinheiten) multiplizieren. Der Mechanismus namens wurde erweitert, so dass er viele Male aufgerufen werden kann. Hier werden wir einen Mechanismus hinzufügen, um zu bestätigen, dass
ein $ 5 der gleiche Wert ist wie der andere $ 5. Übrigens wird die Identität des Objekts mit der speziellen Methode __eq__
von Python bestätigt.
Erstellen Sie einen Test, um sicherzustellen, dass `ein $ 5 einem anderen $ 5 entspricht.
tests/test_money.py
from testtools import TestCase
from example.dollar import Dollar
class MoneyTest(TestCase):
def testMultiplication(self):
five = Dollar(5)
product = five.times(2)
self.assertEqual(10, product.amount)
product = five.times(3)
self.assertEqual(15, product.amount)
def testEquality(self):
self.assertTrue(Dollar(5) == Dollar(5))
self.assertFalse(Dollar(5) == Dollar(6))
Der Test schlägt jedoch fehl, da es in der Klasse "Dollar" keinen Mechanismus gibt, mit dem überprüft werden kann, ob "ein $ 5 dem anderen $ 5 entspricht".
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testEquality FAILED [ 50%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
================================== FAILURES ===================================
___________________________ MoneyTest.testMultiplication ______________________
NOTE: Incompatible Exception Representation, displaying natively:
testtools.testresult.real._StringException: Traceback (most recent call last):
File "/Users/ttsubo/source/study_of_test_driven_development/python/tests/test_money.py", line 13, in testEquality
self.assertTrue(Dollar(5) == Dollar(5))
File "/Users/ttsubo/.pyenv/versions/3.8.0/lib/python3.8/unittest/case.py", line 765, in assertTrue
raise self.failureException(msg)
AssertionError: False is not true
Nutzen Sie die spezielle Methode __eq__
, um` ein $ 5 zu definieren, damit Sie sehen können, dass es dem anderen $ 5 entspricht.
example/dollar.py
class Dollar:
def __init__(self, amount):
self.amount = amount
def __eq__(self, other):
return self.amount == other.amount
def times(self, multiplier):
return Dollar(self.amount * multiplier)
Der Test ist jetzt erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testEquality PASSED [ 50%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
In Kapitel 3 haben wir einen Mechanismus hinzugefügt, um sicherzustellen, dass `ein $ 5 den gleichen Wert hat wie der andere $ 5. Hier werden wir die überlappenden Teile der bisherigen Testbeschreibung mit einer klaren Sicht umgestalten. Ändern Sie außerdem die Instanzvariable "Betrag" des "Dollar" -Objekts in ein privates Mitglied.
MoneyTest: testMultiplication
.Die "times" -Methode der "Dollar" -Klasse gibt ein "Dollar" -Objekt zurück, dessen Betrag multipliziert mit dem "Multiplikator" -Argument in der Instanzvariablen "Betrag" des Dollar-Objekts ist. In der Testbeschreibung, die ich bisher geschrieben habe, ist es schwierig zu sagen, dass das "Dollar" -Objekt zurückgegeben wird, daher werde ich es umgestalten, um die Lesbarkeit zu verbessern.
tests/test_money.py
from testtools import TestCase
from example.dollar import Dollar
class MoneyTest(TestCase):
def testMultiplication(self):
five = Dollar(5)
self.assertEqual(Dollar(10), five.times(2))
self.assertEqual(Dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Dollar(5) == Dollar(5))
self.assertFalse(Dollar(5) == Dollar(6))
Die Tests sind nach dem Refactoring noch erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testEquality PASSED [ 50%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
Ändern Sie die Instanzvariable "Betrag" des "Dollar" -Objekts in ein privates Mitglied.
example/dollar.py
class Dollar:
def __init__(self, amount):
self.__amount = amount
def __eq__(self, other):
return self.__amount == other.__amount
def times(self, multiplier):
return Dollar(self.__amount * multiplier)
Der Test ist erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testEquality PASSED [ 50%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
Bis zu Kapitel 4 multiplizieren Sie als eine der Mehrwährungen den Betrag (Betrag pro Währungseinheit) in Bezug auf die Dollarwährung mit einem numerischen Wert (Anzahl der Währungseinheiten), um den Betrag zu erhalten. Wir haben den Mechanismus von `erkannt. Hier, als eine andere Währung, wird ** Frankenwährung ** den gleichen Mechanismus realisieren.
Fügen Sie einen Test hinzu, damit Sie denselben Test für die Dollarwährung in der Frankenwährung sehen können.
tests/test_money.py
from testtools import TestCase
from example.dollar import Dollar
from example.franc import Franc
class MoneyTest(TestCase):
def testMultiplication(self):
five = Dollar(5)
self.assertEqual(Dollar(10), five.times(2))
self.assertEqual(Dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Dollar(5) == Dollar(5))
self.assertFalse(Dollar(5) == Dollar(6))
def testFrancMultiplication(self):
five = Franc(5)
self.assertEqual(Franc(10), five.times(2))
self.assertEqual(Franc(15), five.times(3))
Stellen Sie den Code bereit, der nur die Klasse "Franc" lädt.
example/franc.py
class Franc:
pass
Der Test schlägt fehl, weil die Franc-Klasse nicht objektiviert werden kann.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testEquality PASSED [ 33%]
tests/test_money.py::MoneyTest::testFrancMultiplication FAILED [ 66%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
================================== FAILURES ===================================
___________________________ MoneyTest.testMultiplication ______________________
NOTE: Incompatible Exception Representation, displaying natively:
testtools.testresult.real._StringException: Traceback (most recent call last):
File "/Users/ttsubo/source/study_of_test_driven_development/tests/test_money.py", line 16, in testFrancMultiplication
five = Franc(5)
TypeError: Franc() takes no arguments
Wir werden die Franc-Klasse definieren, indem wir uns auf das beziehen, was wir in Kapitel 1 getan haben.
example/franc.py
class Franc:
def __init__(self, amount):
self.__amount = amount
def __eq__(self, other):
return self.__amount == other.__amount
def times(self, multiplier):
return Franc(self.__amount * multiplier)
Der Test ist erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testEquality PASSED [ 33%]
tests/test_money.py::MoneyTest::testFrancMultiplication PASSED [ 66%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
In Kapitel 5 erhalten Sie den Betrag, indem Sie den Betrag (Betrag pro Währungseinheit) in Bezug auf die Frankenwährung mit einer Zahl (Anzahl der Währungseinheiten) multiplizieren. Wir haben den Mechanismus von `erkannt, aber die Methode entsprach dem Kopieren des gesamten Mechanismus der Dollarwährung, so dass viele überlappende Teile auftraten. Um Doppelarbeit zu vermeiden, haben zunächst die "einen 5 Dollar, an denen wir in Kapitel 3 gearbeitet haben, den gleichen Wert wie die anderen 5 Dollar" und die "5 Franken" den gleichen Wert wie die anderen 5 Franken. Starten Sie den `` Teil.
Dollar-Währungstest Fügen Sie einen Test hinzu, sodass ein $ 5 dem anderen $ 5 entspricht
in Frankenwährung.
tests/test_money.py
from testtools import TestCase
from example.dollar import Dollar
from example.franc import Franc
class MoneyTest(TestCase):
def testMultiplication(self):
five = Dollar(5)
self.assertEqual(Dollar(10), five.times(2))
self.assertEqual(Dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Dollar(5) == Dollar(5))
self.assertFalse(Dollar(5) == Dollar(6))
self.assertTrue(Franc(5) == Franc(5))
self.assertFalse(Franc(5) == Franc(6))
def testFrancMultiplication(self):
five = Franc(5)
self.assertEqual(Franc(10), five.times(2))
self.assertEqual(Franc(15), five.times(3))
Der hinzugefügte Testteil ist auch ohne Probleme erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testEquality PASSED [ 33%]
tests/test_money.py::MoneyTest::testFrancMultiplication PASSED [ 66%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
Hier führen wir das folgende Refactoring durch.
example/money.py
class Money:
def __init__(self, amount):
self.__amount = amount
def __eq__(self, other):
return self.__amount == other.__amount
example/dollar.py
from example.money import Money
class Dollar(Money):
def __init__(self, amount):
self.__amount = amount
def times(self, multiplier):
return Dollar(self.__amount * multiplier)
example/franc.py
from example.money import Money
class Franc(Money):
def __init__(self, amount):
self.__amount = amount
def times(self, multiplier):
return Franc(self.__amount * multiplier)
Unerwartet wurde der Test gelöscht. </ font>
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testEquality FAILED [ 33%]
tests/test_money.py::MoneyTest::testFrancMultiplication FAILED [ 66%]
tests/test_money.py::MoneyTest::testMultiplication FAILED [100%]
================================== FAILURES ===================================
______________________________ MoneyTest.testEquality _________________________
NOTE: Incompatible Exception Representation, displaying natively:
testtools.testresult.real._StringException: Traceback (most recent call last):
...(snip)
File "/Users/ttsubo/source/study_of_test_driven_development/example/money.py", line 6, in __eq__
return self.__amount == other.__amount
AttributeError: 'Dollar' object has no attribute '_Money__amount'
________________________ MoneyTest.testFrancMultiplication ____________________
NOTE: Incompatible Exception Representation, displaying natively:
testtools.testresult.real._StringException: Traceback (most recent call last):
...(snip)
File "/Users/ttsubo/source/study_of_test_driven_development/example/money.py", line 6, in __eq__
return self.__amount == other.__amount
AttributeError: 'Franc' object has no attribute '_Money__amount'
__________________________ MoneyTest.testMultiplication ______________________
NOTE: Incompatible Exception Representation, displaying natively:
testtools.testresult.real._StringException: Traceback (most recent call last):
...(snip)
File "/Users/ttsubo/source/study_of_test_driven_development/example/money.py", line 6, in __eq__
return self.__amount == other.__amount
AttributeError: 'Dollar' object has no attribute '_Money__amount'
Der Grund, warum der Test fehlschlug, war der Zeitpunkt der Objektivierung von "Dollar" und "Franken", und es war notwendig, den Wert in der Instanzvariablen "Betrag" der übergeordneten Klasse "Geld" zu speichern. Korrigieren Sie daher den Code.
example/dollar.py
from example.money import Money
class Dollar(Money):
def __init__(self, amount):
super(Dollar, self).__init__(amount)
self.__amount = amount
def times(self, multiplier):
return Dollar(self.__amount * multiplier)
example/franc.py
from example.money import Money
class Franc(Money):
def __init__(self, amount):
super(Franc, self).__init__(amount)
self.__amount = amount
def times(self, multiplier):
return Franc(self.__amount * multiplier)
Diesmal war der Test erfolgreich. Aufgrund der testgetriebenen Entwicklung können Sie selbst einen kleinen Refactoring-Fehler sofort feststellen. </ font>
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testEquality PASSED [ 33%]
tests/test_money.py::MoneyTest::testFrancMultiplication PASSED [ 66%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
Bisher haben wir "Dollarwährung" und "Frankenwährung" als mehrere Währungen unterstützt. Die Frage ist nun: "Was ist, wenn Sie ** Dollarwährung ** mit ** Frankenwährung ** vergleichen?"
Fügen Sie einen Test hinzu, um sicherzustellen, dass die ** Dollarwährung ** und die ** Frankenwährung ** nicht gleich sind.
tests/test_money.py
from testtools import TestCase
from example.dollar import Dollar
from example.franc import Franc
class MoneyTest(TestCase):
def testMultiplication(self):
five = Dollar(5)
self.assertEqual(Dollar(10), five.times(2))
self.assertEqual(Dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Dollar(5) == Dollar(5))
self.assertFalse(Dollar(5) == Dollar(6))
self.assertTrue(Franc(5) == Franc(5))
self.assertFalse(Franc(5) == Franc(6))
self.assertFalse(Franc(5) == Dollar(5))
def testFrancMultiplication(self):
five = Franc(5)
self.assertEqual(Franc(10), five.times(2))
self.assertEqual(Franc(15), five.times(3))
Der Test schlägt fehl. Mit anderen Worten, das Ergebnis ist, dass der Dollar und der Franken gleich sind.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testEquality FAILED [ 33%]
tests/test_money.py::MoneyTest::testFrancMultiplication PASSED [ 66%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
================================== FAILURES ===================================
______________________________ MoneyTest.testEquality _________________________
NOTE: Incompatible Exception Representation, displaying natively:
testtools.testresult.real._StringException: Traceback (most recent call last):
File "/Users/ttsubo/source/study_of_test_driven_development/tests/test_money.py", line 16, in testEquality
self.assertFalse(Franc(5) == Dollar(5))
File "/Users/ttsubo/.pyenv/versions/3.8.0/lib/python3.8/unittest/case.py", line 759, in assertFalse
raise self.failureException(msg)
AssertionError: True is not false
Da es notwendig war, das "Dollar" -Objekt und das "Franc" -Objekt zu vergleichen, um den Äquivalenzvergleich durchzuführen, modifizieren Sie den Teil der Beurteilungslogik der speziellen Methode "eq" der "Money" -Klasse.
example/money.py
class Money:
def __init__(self, amount):
self.__amount = amount
def __eq__(self, other):
return (self.__amount == other.__amount
and self.__class__.__name__ == other.__class__.__name__)
Diesmal war der Test erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testEquality PASSED [ 33%]
tests/test_money.py::MoneyTest::testFrancMultiplication PASSED [ 66%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
In den Kapiteln 6 und 7 haben wir den Äquivalenzvergleich überarbeitet. Von nun an multiplizieren Sie für eine Weile den Betrag (Betrag pro Währungseinheit) mit einer Zahl (Anzahl der Währungseinheiten), um den Betrag zu erhalten. Versuche, Duplikate im Mechanismus zu entfernen.
Hierbei wird angenommen, dass das folgende Refactoring als erster Schritt durchgeführt wird, um den doppelten Teil der in den Klassen "Dollar" und "Franc" definierten "Zeiten" -Methode zu eliminieren und in der "Geld" -Klasse gemeinsam zu machen. Und behebe den Test.
tests/test_money.py
from testtools import TestCase
from example.money import Money
class MoneyTest(TestCase):
def testMultiplication(self):
five = Money.dollar(5)
self.assertEqual(Money.dollar(10), five.times(2))
self.assertEqual(Money.dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Money.dollar(5) == Money.dollar(5))
self.assertFalse(Money.dollar(5) == Money.dollar(6))
self.assertTrue(Money.franc(5) == Money.franc(5))
self.assertFalse(Money.franc(5) == Money.franc(6))
self.assertFalse(Money.franc(5) == Money.dollar(5))
def testFrancMultiplication(self):
five = Money.franc(5)
self.assertEqual(Money.franc(10), five.times(2))
self.assertEqual(Money.franc(15), five.times(3))
Hier wird das folgende Refactoring als erster Schritt durchgeführt, um den doppelten Teil der in den Klassen "Dollar" und "Franc" definierten "Zeiten" -Methode zu eliminieren und in der "Geld" -Klasse gemeinsam zu machen.
example/money.py
from abc import ABCMeta, abstractmethod
from example.dollar import Dollar
from example.franc import Franc
class Money(metaclass=ABCMeta):
def __init__(self, amount):
self.__amount = amount
def __eq__(self, other):
return (self.__amount == other.__amount
and self.__class__.__name__ == other.__class__.__name__)
@abstractmethod
def times(self, multiplier):
pass
@classmethod
def dollar(cls, amount):
return Dollar(amount)
@classmethod
def franc(cls, amount):
return Franc(amount)
Der Test konnte nicht gestartet werden und es ist ein Fehler aufgetreten. Es scheint, dass die Ursache der zirkuläre Import von Python-Modulen ist.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testEquality FAILED [ 33%]
tests/test_money.py::MoneyTest::testFrancMultiplication FAILED [ 66%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
=================================== ERRORs ====================================
ImportError while importing test module '/Users/ttsubo/source/study_of_test_driven_development/tests/test_money.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests/test_money.py:2: in <module>
from example.money import Money
example/money.py:2: in <module>
from example.dollar import Dollar
example/dollar.py:1: in <module>
from example.money import Money
E ImportError: cannot import name 'Money' from partially initialized module 'example.money' (most likely due to a circular import) (/Users/ttsubo/source/study_of_test_driven_development/example/money.py)
Ändern Sie die in money.py zu definierenden Klassen "Dollar" und "Franc", da dies auf den zirkulären Import von Python-Modulen zurückzuführen ist.
example/money.py
from abc import ABCMeta, abstractmethod
class Money(metaclass=ABCMeta):
def __init__(self, amount):
self.__amount = amount
def __eq__(self, other):
return (self.__amount == other.__amount
and self.__class__.__name__ == other.__class__.__name__)
@abstractmethod
def times(self, multiplier):
pass
@classmethod
def dollar(cls, amount):
return Dollar(amount)
@classmethod
def franc(cls, amount):
return Franc(amount)
class Dollar(Money):
def __init__(self, amount):
super(Dollar, self).__init__(amount)
self.__amount = amount
def times(self, multiplier):
return Dollar(self.__amount * multiplier)
class Franc(Money):
def __init__(self, amount):
super(Franc, self).__init__(amount)
self.__amount = amount
def times(self, multiplier):
return Franc(self.__amount * multiplier)
Diesmal war der Test erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testEquality PASSED [ 33%]
tests/test_money.py::MoneyTest::testFrancMultiplication PASSED [ 66%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
Fahren Sie mit dem vorherigen Kapitel fort und multiplizieren Sie den Betrag (Betrag pro Währungseinheit) mit einem numerischen Wert (Anzahl der Währungseinheiten), um den Betrag zu erhalten. Versuche, Duplikate im Mechanismus zu entfernen.
Hier werden die Objekte "Dollar" und "Franc" als erster Schritt verwendet, um die Verdoppelung der in den Klassen "Dollar" und "Franc" definierten "Zeiten" -Methode zu beseitigen und sie in der Klasse "Geld" gemeinsam zu machen. Fügen Sie den Test testCurrency
hinzu, vorausgesetzt, Sie wenden das Konzept der " Währung " zur Unterscheidung an.
tests/test_money.py
from testtools import TestCase
from example.money import Money
class MoneyTest(TestCase):
def testMultiplication(self):
five = Money.dollar(5)
self.assertEqual(Money.dollar(10), five.times(2))
self.assertEqual(Money.dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Money.dollar(5) == Money.dollar(5))
self.assertFalse(Money.dollar(5) == Money.dollar(6))
self.assertTrue(Money.franc(5) == Money.franc(5))
self.assertFalse(Money.franc(5) == Money.franc(6))
self.assertFalse(Money.franc(5) == Money.dollar(5))
def testFrancMultiplication(self):
five = Money.franc(5)
self.assertEqual(Money.franc(10), five.times(2))
self.assertEqual(Money.franc(15), five.times(3))
def testCurrency(self):
self.assertEqual("USD", Money.dollar(1).currency())
self.assertEqual("CHF", Money.franc(1).currency())
Hier werden die Objekte "Dollar" und "Franc" als erster Schritt verwendet, um die Verdoppelung der in den Klassen "Dollar" und "Franc" definierten "Zeiten" -Methode zu beseitigen und sie in der Klasse "Geld" gemeinsam zu machen. Wir wenden das Konzept der "Währung" an, das eine Unterscheidung treffen soll.
example/money.py
from abc import ABCMeta, abstractmethod
class Money(metaclass=ABCMeta):
def __init__(self, amount, currency):
self.__amount = amount
self.__currency = currency
def __eq__(self, other):
return (self.__amount == other.__amount
and self.__class__.__name__ == other.__class__.__name__)
@abstractmethod
def times(self, multiplier):
pass
def currency(self):
return self.__currency
@classmethod
def dollar(cls, amount):
return Dollar(amount, "USD")
@classmethod
def franc(cls, amount):
return Franc(amount, "CHF")
class Dollar(Money):
def __init__(self, amount, currency):
super().__init__(amount, currency)
self.__amount = amount
def times(self, multiplier):
return Money.dollar(self.__amount * multiplier)
class Franc(Money):
def __init__(self, amount, currency):
super().__init__(amount, currency)
self.__amount = amount
def times(self, multiplier):
return Money.franc(self.__amount * multiplier)
Der Test war erwartungsgemäß erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testCurrency PASSED [ 25%]
tests/test_money.py::MoneyTest::testEquality PASSED [ 50%]
tests/test_money.py::MoneyTest::testFrancMultiplication PASSED [ 75%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
Multiplizieren Sie den Betrag (Betrag pro Währungseinheit), den Sie bisher begonnen haben, mit einem numerischen Wert (Anzahl der Währungseinheiten), um den Betrag zu erhalten. Schließen Sie den Versuch ab, den duplizierten Teil des Mechanismus namens `zu entfernen.
Multiplizieren Sie den Betrag (Betrag pro Währungseinheit) mit der Anzahl (Anzahl der Währungseinheiten), um den Betrag zu erhalten. Fügen Sie den Test
testDifferentClassEquality hinzu, vorausgesetzt, das Refactoring zum Entfernen von Duplikaten im
Mechanismus ist abgeschlossen.
tests/test_money.py
from testtools import TestCase
from example.money import Money, Franc
class MoneyTest(TestCase):
def testMultiplication(self):
five = Money.dollar(5)
self.assertEqual(Money.dollar(10), five.times(2))
self.assertEqual(Money.dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Money.dollar(5) == Money.dollar(5))
self.assertFalse(Money.dollar(5) == Money.dollar(6))
self.assertTrue(Money.franc(5) == Money.franc(5))
self.assertFalse(Money.franc(5) == Money.franc(6))
self.assertFalse(Money.franc(5) == Money.dollar(5))
def testFrancMultiplication(self):
five = Money.franc(5)
self.assertEqual(Money.franc(10), five.times(2))
self.assertEqual(Money.franc(15), five.times(3))
def testCurrency(self):
self.assertEqual("USD", Money.dollar(1).currency())
self.assertEqual("CHF", Money.franc(1).currency())
def testDifferentClassEquality(self):
self.assertTrue(Money(10, "CHF") == Franc(10, "CHF"))
Führen Sie das folgende Refactoring durch:
example/money.py
class Money():
def __init__(self, amount, currency):
self.__amount = amount
self.__currency = currency
def __eq__(self, other):
return (self.__amount == other.__amount
and self.currency() == other.currency())
def times(self, multiplier):
return Money(self.__amount * multiplier, self.__currency)
def currency(self):
return self.__currency
@classmethod
def dollar(cls, amount):
return Dollar(amount, "USD")
@classmethod
def franc(cls, amount):
return Franc(amount, "CHF")
class Dollar(Money):
def __init__(self, amount, currency):
super().__init__(amount, currency)
class Franc(Money):
def __init__(self, amount, currency):
super().__init__(amount, currency)
Der Test war erwartungsgemäß erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testCurrency PASSED [ 20%]
tests/test_money.py::MoneyTest::testDifferentClassEquality PASSED [ 40%]
tests/test_money.py::MoneyTest::testEquality PASSED [ 60%]
tests/test_money.py::MoneyTest::testFrancMultiplication PASSED [ 80%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
Die Klassen "Dollar" und "Franc" können ebenfalls gestrichen werden, wodurch das bisherige Refactoring abgeschlossen wird.
Multiplizieren Sie den Betrag (Betrag pro Währungseinheit) mit der Anzahl (Anzahl der Währungseinheiten), um den Betrag zu erhalten. Unter der Annahme, dass das Refactoring des als
bezeichneten Mechanismus abgeschlossen ist, wird auch der Test selbst refactored.
tests/test_money.py
from testtools import TestCase
from example.money import Money
class MoneyTest(TestCase):
def testMultiplication(self):
five = Money.dollar(5)
self.assertEqual(Money.dollar(10), five.times(2))
self.assertEqual(Money.dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Money.dollar(5) == Money.dollar(5))
self.assertFalse(Money.dollar(5) == Money.dollar(6))
self.assertFalse(Money.franc(5) == Money.dollar(5))
def testCurrency(self):
self.assertEqual("USD", Money.dollar(1).currency())
self.assertEqual("CHF", Money.franc(1).currency())
Sie müssen die Klassen "Dollar" und "Franken" nicht definieren, da Sie bereits im Objekt "Geld" zwischen "** Dollarwährung " und " Frankenwährung **" unterscheiden können. Wird sein. Entfernen Sie die Klassen "Dollar", "Franc", um das Refactoring abzuschließen.
example/money.py
class Money():
def __init__(self, amount, currency):
self.__amount = amount
self.__currency = currency
def __eq__(self, other):
return (self.__amount == other.__amount
and self.currency() == other.currency())
def times(self, multiplier):
return Money(self.__amount * multiplier, self.__currency)
def currency(self):
return self.__currency
@classmethod
def dollar(cls, amount):
return Money(amount, "USD")
@classmethod
def franc(cls, amount):
return Money(amount, "CHF")
Der Test war erwartungsgemäß erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testCurrency PASSED [ 33%]
tests/test_money.py::MoneyTest::testEquality PASSED [ 66%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [100%]
Fügen Sie daraus zwei verschiedene Währungsbeträge hinzu, um den umgerechneten Betrag basierend auf dem Wechselkurs zwischen den Währungen zu erhalten. Wir werden einen Mechanismus realisieren, der die Anforderungen von `erfüllt. Darüber hinaus scheint es, dass diese Anforderung in die folgenden zwei Aufgaben zerlegt werden kann.
$5 + $5 = $10
Addieren Sie zuerst die zwei Beträge, um den Betrag zu erhalten. Als Mechanismus von fahren wir mit der Codierung fort, so dass
$ 5 + $ 5 = $ 10` gilt.
Addiere zwei Beträge, um den Betrag zu erhalten. Fügen Sie den Test
testSimpleAddition hinzu, um zu sehen, wie
funktioniert.
Darüber hinaus werden wir die folgenden zwei Konzepte für zukünftige Designs berücksichtigen.
tests/test_money.py
from testtools import TestCase
from example.money import Money
from example.bank import Bank
class MoneyTest(TestCase):
def testMultiplication(self):
five = Money.dollar(5)
self.assertEqual(Money.dollar(10), five.times(2))
self.assertEqual(Money.dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Money.dollar(5) == Money.dollar(5))
self.assertFalse(Money.dollar(5) == Money.dollar(6))
self.assertFalse(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.plus(five)
bank = Bank()
reduced = bank.reduce(_sum, "USD")
self.assertEqual(Money.dollar(10), reduced)
Die in diesem Kapitel behandelte Implementierung ist ziemlich kompliziert, daher wird es eine ziemlich große Änderung sein, aber es sieht so aus.
―― Addiere zwei Beträge, um den Betrag zu erhalten. Um den
Mechanismus zu implementieren, fügen Sie der Money
Klasse eine Plus
Methode hinzu.
example/money.py
from example.expression import Expression
class Money(Expression):
def __init__(self, amount, currency):
self.__amount = amount
self.__currency = currency
def __eq__(self, other):
return (self.__amount == other.__amount
and self.currency() == other.currency())
def times(self, multiplier):
return Money(self.__amount * multiplier, self.__currency)
def plus(self, addend):
return Money(self.__amount + addend.__amount, self.__currency)
def currency(self):
return self.__currency
@classmethod
def dollar(cls, amount):
return Money(amount, "USD")
@classmethod
def franc(cls, amount):
return Money(amount, "CHF")
example/bank.py
from example.money import Money
class Bank():
def reduce(self, source , toCurrency):
return Money.dollar(10)
example/expression.py
from abc import ABCMeta
class Expression(metaclass=ABCMeta):
pass
Der Test ist erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testCurrency PASSED [ 25%]
tests/test_money.py::MoneyTest::testEquality PASSED [ 50%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [ 75%]
tests/test_money.py::MoneyTest::testSimpleAddition PASSED [100%]
Fügen Sie weiterhin zwei Beträge hinzu, um den Betrag zu erhalten. Fahren Sie als Mechanismus von mit der Codierung fort, sodass
$ 5 + $ 5 = $ 10` gilt.
Letztes Mal werden wir das Verhalten der "Reduce" -Methode der "Bank" -Klasse starten, wo sie als temporäre Implementierung definiert wurde.
Da die Anstrengungen hier wahrscheinlich recht umfangreich sind, werden wir außerdem mit den folgenden Schritten fortfahren.
--STEP1: Schreiben Sie die Verarbeitung von $ 5 + $ 5
--STEP2: Verwirklichen Sie die vorübergehende Implementierung der "Reduce" -Methode der "Bank" -Klasse
--STEP3: Verwirklichen Sie die vorübergehende Implementierung der "Reduce" -Methode der "Bank" -Klasse (Forts.)
$ 5 + $ 5
Als erster Schritt zur Realisierung von "$ 5 + $ 5 = $ 10" wird die Verarbeitung des Teils von "$ 5 + $ 5" durchgeführt.
Fügen Sie den Test testPlusReturnsSum
hinzu.
tests/test_money.py
from testtools import TestCase
from example.money import Money
from example.bank import Bank
class MoneyTest(TestCase):
def testMultiplication(self):
five = Money.dollar(5)
self.assertEqual(Money.dollar(10), five.times(2))
self.assertEqual(Money.dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Money.dollar(5) == Money.dollar(5))
self.assertFalse(Money.dollar(5) == Money.dollar(6))
self.assertFalse(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.plus(five)
bank = Bank()
reduced = bank.reduce(_sum, "USD")
self.assertEqual(Money.dollar(10), reduced)
def testPlusReturnsSum(self):
five = Money.dollar(5)
_sum = five.plus(five)
self.assertEqual(five, _sum.augend)
self.assertEqual(five, _sum.addend)
Nehmen Sie folgende Änderungen vor:
example/money.py
from example.expression import Expression
class Money(Expression):
def __init__(self, amount, currency):
self.__amount = amount
self.__currency = currency
def __eq__(self, other):
return (self.__amount == other.__amount
and self.currency() == other.currency())
def times(self, multiplier):
return Money(self.__amount * multiplier, self.__currency)
def plus(self, addend):
return Sum(self, addend)
def currency(self):
return self.__currency
@classmethod
def dollar(cls, amount):
return Money(amount, "USD")
@classmethod
def franc(cls, amount):
return Money(amount, "CHF")
class Sum(Expression):
def __init__(self, augend, addend):
self.augend = augend
self.addend = addend
Der Test ist erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testCurrency PASSED [ 20%]
tests/test_money.py::MoneyTest::testEquality PASSED [ 40%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [ 60%]
tests/test_money.py::MoneyTest::testPlusReturnsSum PASSED [ 80%]
tests/test_money.py::MoneyTest::testSimpleAddition PASSED [100%]
Wir werden die "Reduce" -Methode der "Bank" -Klasse verwirklichen. Hier zielen wir auf das Summenobjekt.
Fügen Sie den Test testReduceSum
hinzu.
tests/test_money.py
from testtools import TestCase
from example.money import Money, Sum
from example.bank import Bank
class MoneyTest(TestCase):
def testMultiplication(self):
five = Money.dollar(5)
self.assertEqual(Money.dollar(10), five.times(2))
self.assertEqual(Money.dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Money.dollar(5) == Money.dollar(5))
self.assertFalse(Money.dollar(5) == Money.dollar(6))
self.assertFalse(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.plus(five)
bank = Bank()
reduced = bank.reduce(_sum, "USD")
self.assertEqual(Money.dollar(10), reduced)
def testPlusReturnsSum(self):
five = Money.dollar(5)
_sum = five.plus(five)
self.assertEqual(five, _sum.augend)
self.assertEqual(five, _sum.addend)
def testReduceSum(self):
_sum = Sum(Money.dollar(3), Money.dollar(4))
bank = Bank()
result = bank.reduce(_sum, "USD")
self.assertEqual(Money.dollar(7), result)
Nehmen Sie folgende Änderungen vor:
example/money.py
from example.expression import Expression
class Money(Expression):
def __init__(self, amount, currency):
self.__amount = amount
self.__currency = currency
def __eq__(self, other):
return (self.__amount == other.__amount
and self.currency() == other.currency())
def times(self, multiplier):
return Money(self.__amount * multiplier, self.__currency)
def plus(self, addend):
return Sum(self, addend)
def amount(self):
return self.__amount
def currency(self):
return self.__currency
@classmethod
def dollar(cls, amount):
return Money(amount, "USD")
@classmethod
def franc(cls, amount):
return Money(amount, "CHF")
class Sum(Expression):
def __init__(self, augend, addend):
self.augend = augend
self.addend = addend
def reduce(self, toCurrency):
amount = self.augend.amount() + self.addend.amount()
return Money(amount, toCurrency)
example/bank.py
class Bank():
def reduce(self, source , toCurrency):
return source.reduce(toCurrency)
Der Test ist erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testCurrency PASSED [ 16%]
tests/test_money.py::MoneyTest::testEquality PASSED [ 33%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [ 50%]
tests/test_money.py::MoneyTest::testPlusReturnsSum PASSED [ 66%]
tests/test_money.py::MoneyTest::testReduceSum PASSED [ 83%]
tests/test_money.py::MoneyTest::testSimpleAddition PASSED [100%]
Wir werden die "Reduce" -Methode der "Bank" -Klasse verwirklichen. Hier zielen wir auf das Objekt "Geld".
Fügen Sie den Test testReduceMoney
hinzu.
tests/test_money.py
from testtools import TestCase
from example.money import Money, Sum
from example.bank import Bank
class MoneyTest(TestCase):
def testMultiplication(self):
five = Money.dollar(5)
self.assertEqual(Money.dollar(10), five.times(2))
self.assertEqual(Money.dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Money.dollar(5) == Money.dollar(5))
self.assertFalse(Money.dollar(5) == Money.dollar(6))
self.assertFalse(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.plus(five)
bank = Bank()
reduced = bank.reduce(_sum, "USD")
self.assertEqual(Money.dollar(10), reduced)
def testPlusReturnsSum(self):
five = Money.dollar(5)
_sum = five.plus(five)
self.assertEqual(five, _sum.augend)
self.assertEqual(five, _sum.addend)
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)
Nehmen Sie folgende Änderungen vor:
example/money.py
from example.expression import Expression
class Money(Expression):
def __init__(self, amount, currency):
self.__amount = amount
self.__currency = currency
def __eq__(self, other):
return (self.__amount == other.__amount
and self.currency() == other.currency())
def times(self, multiplier):
return Money(self.__amount * multiplier, self.__currency)
def plus(self, addend):
return Sum(self, addend)
def reduce(self, toCurrency):
return self
def amount(self):
return self.__amount
def currency(self):
return self.__currency
@classmethod
def dollar(cls, amount):
return Money(amount, "USD")
@classmethod
def franc(cls, amount):
return Money(amount, "CHF")
class Sum(Expression):
def __init__(self, augend, addend):
self.augend = augend
self.addend = addend
def reduce(self, toCurrency):
amount = self.augend.amount() + self.addend.amount()
return Money(amount, toCurrency)
example/expression.py
from abc import ABCMeta, abstractmethod
class Expression(metaclass=ABCMeta):
@abstractmethod
def reduce(self, toCurrency):
pass
Der Test ist erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testCurrency PASSED [ 14%]
tests/test_money.py::MoneyTest::testEquality PASSED [ 28%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [ 42%]
tests/test_money.py::MoneyTest::testPlusReturnsSum PASSED [ 57%]
tests/test_money.py::MoneyTest::testReduceMoney PASSED [ 71%]
tests/test_money.py::MoneyTest::testReduceSum PASSED [ 85%]
tests/test_money.py::MoneyTest::testSimpleAddition PASSED [100%]
Hier werden wir den Prozess der Umrechnung von 2 Franken in 1 Dollar realisieren.
--STEP1: Verarbeitung zur Umrechnung von 2 Franken in 1 Dollar (Wechselkurs vorläufig implementiert) --STEP2: Verarbeitung zur Umrechnung von 2 Franken in 1 Dollar (Implementierung der Wechselkurstabelle)
Wir werden den Prozess der Umrechnung von 2 Franken in 1 Dollar realisieren. Es wird jedoch davon ausgegangen, dass der Wechselkurs-> USD: CHF = 2: 1 ist.
Fügen Sie den Test testReduceMoneyDifferentCurrency
hinzu.
tests/test_money.py
from testtools import TestCase
from example.money import Money, Sum
from example.bank import Bank
class MoneyTest(TestCase):
def testMultiplication(self):
five = Money.dollar(5)
self.assertEqual(Money.dollar(10), five.times(2))
self.assertEqual(Money.dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Money.dollar(5) == Money.dollar(5))
self.assertFalse(Money.dollar(5) == Money.dollar(6))
self.assertFalse(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.plus(five)
bank = Bank()
reduced = bank.reduce(_sum, "USD")
self.assertEqual(Money.dollar(10), reduced)
def testPlusReturnsSum(self):
five = Money.dollar(5)
_sum = five.plus(five)
self.assertEqual(five, _sum.augend)
self.assertEqual(five, _sum.addend)
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)
Nehmen Sie folgende Änderungen vor:
--Add_rateMethode zur
Bank` Klasse (temporäre Implementierung)
example/money.py
from example.expression import Expression
class Money(Expression):
def __init__(self, amount, currency):
self.__amount = amount
self.__currency = currency
def __eq__(self, other):
return (self.__amount == other.__amount
and self.currency() == other.currency())
def times(self, multiplier):
return Money(self.__amount * multiplier, self.__currency)
def plus(self, addend):
return Sum(self, addend)
def reduce(self, bank, toCurrency):
rate = bank.rate(self.__currency, toCurrency)
return Money(self.__amount / rate, toCurrency)
def amount(self):
return self.__amount
def currency(self):
return self.__currency
@classmethod
def dollar(cls, amount):
return Money(amount, "USD")
@classmethod
def franc(cls, amount):
return Money(amount, "CHF")
class Sum(Expression):
def __init__(self, augend, addend):
self.augend = augend
self.addend = addend
def reduce(self, bank, toCurrency):
amount = self.augend.amount() + self.addend.amount()
return Money(amount, toCurrency)
example/bank.py
class Bank():
def reduce(self, source , toCurrency):
return source.reduce(self, toCurrency)
def add_rate(self, fromCurrency, toCurrency, rate):
pass
def rate(self, fromCurrency, toCurrency):
return 2 if (fromCurrency == "CHF" and toCurrency == "USD") else 1
example/expression.py
from abc import ABCMeta, abstractmethod
class Expression(metaclass=ABCMeta):
@abstractmethod
def reduce(self, bank, toCurrency):
pass
Der Test ist erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testCurrency PASSED [ 12%]
tests/test_money.py::MoneyTest::testEquality PASSED [ 25%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [ 37%]
tests/test_money.py::MoneyTest::testPlusReturnsSum PASSED [ 50%]
tests/test_money.py::MoneyTest::testReduceMoney PASSED [ 62%]
tests/test_money.py::MoneyTest::testReduceMoneyDifferentCurrency PASSED [ 75%]
tests/test_money.py::MoneyTest::testReduceSum PASSED [ 87%]
tests/test_money.py::MoneyTest::testSimpleAddition PASSED [100%]
Basierend auf der Wechselkurstabelle werden wir den Prozess der Umrechnung von 2 Franken in 1 Dollar realisieren.
Fügen Sie den Test testIdentityRate
hinzu.
tests/test_money.py
from testtools import TestCase
from example.money import Money, Sum
from example.bank import Bank
class MoneyTest(TestCase):
def testMultiplication(self):
five = Money.dollar(5)
self.assertEqual(Money.dollar(10), five.times(2))
self.assertEqual(Money.dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Money.dollar(5) == Money.dollar(5))
self.assertFalse(Money.dollar(5) == Money.dollar(6))
self.assertFalse(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.plus(five)
bank = Bank()
reduced = bank.reduce(_sum, "USD")
self.assertEqual(Money.dollar(10), reduced)
def testPlusReturnsSum(self):
five = Money.dollar(5)
_sum = five.plus(five)
self.assertEqual(five, _sum.augend)
self.assertEqual(five, _sum.addend)
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"))
Nehmen Sie folgende Änderungen vor:
example/bank.py
class Bank():
def __init__(self):
self._rates = {}
def reduce(self, source , toCurrency):
return source.reduce(self, toCurrency)
def add_rate(self, fromCurrency, toCurrency, rate):
target_rate = "{0}:{1}".format(fromCurrency, toCurrency)
self._rates[target_rate] = rate
def rate(self, fromCurrency, toCurrency):
target_rate = "{0}:{1}".format(fromCurrency, toCurrency)
if fromCurrency == toCurrency:
return 1
return self._rates.get(target_rate)
Der Test ist erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testCurrency PASSED [ 11%]
tests/test_money.py::MoneyTest::testEquality PASSED [ 22%]
tests/test_money.py::MoneyTest::testIdentityRate PASSED [ 33%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [ 44%]
tests/test_money.py::MoneyTest::testPlusReturnsSum PASSED [ 55%]
tests/test_money.py::MoneyTest::testReduceMoney PASSED [ 66%]
tests/test_money.py::MoneyTest::testReduceMoneyDifferentCurrency PASSED [ 77%]
tests/test_money.py::MoneyTest::testReduceSum PASSED [ 88%]
tests/test_money.py::MoneyTest::testSimpleAddition PASSED [100%]
Fügen Sie bisher zwei verschiedene Währungsbeträge hinzu und erhalten Sie den umgerechneten Betrag basierend auf dem Wechselkurs zwischen den Währungen. Wir haben uns zum Ziel gesetzt, einen Mechanismus zu realisieren, der die Anforderungen von `erfüllt. Hier beginnen wir mit der Aufgabe "5 $ + 10 CHF = 10 $ (bei einer Rate von 2: 1)".
Fügen Sie den Test testMixedAddition
hinzu.
tests/test_money.py
from testtools import TestCase
from example.money import Money, Sum
from example.bank import Bank
class MoneyTest(TestCase):
def testMultiplication(self):
five = Money.dollar(5)
self.assertEqual(Money.dollar(10), five.times(2))
self.assertEqual(Money.dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Money.dollar(5) == Money.dollar(5))
self.assertFalse(Money.dollar(5) == Money.dollar(6))
self.assertFalse(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.plus(five)
bank = Bank()
reduced = bank.reduce(_sum, "USD")
self.assertEqual(Money.dollar(10), reduced)
def testPlusReturnsSum(self):
five = Money.dollar(5)
_sum = five.plus(five)
self.assertEqual(five, _sum.augend)
self.assertEqual(five, _sum.addend)
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"))
def testMixedAddition(self):
fiveBucks = Money.dollar(5)
tenFrancs = Money.franc(10)
bank = Bank()
bank.add_rate("CHF", "USD", 2)
result = bank.reduce(fiveBucks.plus(tenFrancs), "USD")
self.assertEqual(Money.dollar(10), result)
Nehmen Sie folgende Änderungen vor:
example/money.py
from example.expression import Expression
class Money(Expression):
def __init__(self, amount, currency):
self.__amount = amount
self.__currency = currency
def __eq__(self, other):
return (self.__amount == other.__amount
and self.currency() == other.currency())
def times(self, multiplier):
return Money(self.__amount * multiplier, self.__currency)
def plus(self, addend):
return Sum(self, addend)
def reduce(self, bank, toCurrency):
rate = bank.rate(self.__currency, toCurrency)
return Money(self.__amount / rate, toCurrency)
def amount(self):
return self.__amount
def currency(self):
return self.__currency
@classmethod
def dollar(cls, amount):
return Money(amount, "USD")
@classmethod
def franc(cls, amount):
return Money(amount, "CHF")
class Sum(Expression):
def __init__(self, augend, addend):
self.augend = augend
self.addend = addend
def reduce(self, bank, toCurrency):
amount = self.augend.reduce(bank, toCurrency).amount() + \
self.addend.reduce(bank, toCurrency).amount()
return Money(amount, toCurrency)
def plus(self, addend):
pass
example/expression.py
from abc import ABCMeta, abstractmethod
class Expression(metaclass=ABCMeta):
@abstractmethod
def plus(self, addend):
pass
@abstractmethod
def reduce(self, bank, toCurrency):
pass
Der Test ist erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testCurrency PASSED [ 10%]
tests/test_money.py::MoneyTest::testEquality PASSED [ 20%]
tests/test_money.py::MoneyTest::testIdentityRate PASSED [ 30%]
tests/test_money.py::MoneyTest::testMixedAddition PASSED [ 40%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [ 50%]
tests/test_money.py::MoneyTest::testPlusReturnsSum PASSED [ 60%]
tests/test_money.py::MoneyTest::testReduceMoney PASSED [ 70%]
tests/test_money.py::MoneyTest::testReduceMoneyDifferentCurrency PASSED [ 80%]
tests/test_money.py::MoneyTest::testReduceSum PASSED [ 90%]
tests/test_money.py::MoneyTest::testSimpleAddition PASSED [100%]
Schließlich addieren Sie die zwei verschiedenen Währungen und erhalten den umgerechneten Betrag basierend auf dem Wechselkurs zwischen den Währungen. Wir werden die Realisierung eines Mechanismus abschließen, der die Anforderungen von `erfüllt.
--STEP1: Beende die Plus-Methode der Sum-Klasse --STEP2: Beende die "times" -Methode der "Sum" -Klasse
Vervollständige die Plus-Methode der Sum-Klasse.
Fügen Sie den Test testSumPlusMoney
hinzu.
tests/test_money.py
from testtools import TestCase
from example.money import Money, Sum
from example.bank import Bank
class MoneyTest(TestCase):
def testMultiplication(self):
five = Money.dollar(5)
self.assertEqual(Money.dollar(10), five.times(2))
self.assertEqual(Money.dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Money.dollar(5) == Money.dollar(5))
self.assertFalse(Money.dollar(5) == Money.dollar(6))
self.assertFalse(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.plus(five)
bank = Bank()
reduced = bank.reduce(_sum, "USD")
self.assertEqual(Money.dollar(10), reduced)
def testPlusReturnsSum(self):
five = Money.dollar(5)
_sum = five.plus(five)
self.assertEqual(five, _sum.augend)
self.assertEqual(five, _sum.addend)
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"))
def testMixedAddition(self):
fiveBucks = Money.dollar(5)
tenFrancs = Money.franc(10)
bank = Bank()
bank.add_rate("CHF", "USD", 2)
result = bank.reduce(fiveBucks.plus(tenFrancs), "USD")
self.assertEqual(Money.dollar(10), result)
def testSumPlusMoney(self):
fiveBucks = Money.dollar(5)
tenFrancs = Money.franc(10)
bank = Bank()
bank.add_rate("CHF", "USD", 2)
_sum = Sum(fiveBucks, tenFrancs).plus(fiveBucks)
result = bank.reduce(_sum, "USD")
self.assertEqual(Money.dollar(15), result)
Nehmen Sie folgende Änderungen vor:
example/money.py
from example.expression import Expression
class Money(Expression):
def __init__(self, amount, currency):
self.amount = amount
self._currency = currency
def __eq__(self, other):
return (self.amount == other.amount
and self.currency() == other.currency())
def times(self, multiplier):
return Money(self.amount * multiplier, self._currency)
def plus(self, addend):
return Sum(self, addend)
def reduce(self, bank, toCurrency):
rate = bank.rate(self.currency(), toCurrency)
return Money(self.amount / rate, toCurrency)
def currency(self):
return self._currency
@classmethod
def dollar(cls, amount):
return Money(amount, "USD")
@classmethod
def franc(cls, amount):
return Money(amount, "CHF")
class Sum(Expression):
def __init__(self, augend, addend):
self.augend = augend
self.addend = addend
def reduce(self, bank, toCurrency):
amount = self.augend.reduce(bank, toCurrency).amount + \
self.addend.reduce(bank, toCurrency).amount
return Money(amount, toCurrency)
def plus(self, addend):
return Sum(self, addend)
example/bank.py
class Bank():
def __init__(self):
self._rates = {}
def reduce(self, source , toCurrency):
return source.reduce(self, toCurrency)
def add_rate(self, fromCurrency, toCurrency, rate):
self._rates[(fromCurrency, toCurrency)] = rate
def rate(self, fromCurrency, toCurrency):
if fromCurrency == toCurrency:
return 1
return self._rates.get((fromCurrency, toCurrency))
Der Test ist erfolgreich.
$ pytest -v
...(snip)
tests/test_money.py::MoneyTest::testCurrency PASSED [ 9%]
tests/test_money.py::MoneyTest::testEquality PASSED [ 18%]
tests/test_money.py::MoneyTest::testIdentityRate PASSED [ 27%]
tests/test_money.py::MoneyTest::testMixedAddition PASSED [ 36%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [ 45%]
tests/test_money.py::MoneyTest::testPlusReturnsSum PASSED [ 54%]
tests/test_money.py::MoneyTest::testReduceMoney PASSED [ 63%]
tests/test_money.py::MoneyTest::testReduceMoneyDifferentCurrency PASSED [ 72%]
tests/test_money.py::MoneyTest::testReduceSum PASSED [ 81%]
tests/test_money.py::MoneyTest::testSimpleAddition PASSED [ 90%]
tests/test_money.py::MoneyTest::testSumPlusMoney PASSED [100%]
Vervollständige die times
Methode der Sum
Klasse.
Fügen Sie den Test testSumTimes
hinzu.
tests/test_money.py
from testtools import TestCase
from example.money import Money, Sum
from example.bank import Bank
class MoneyTest(TestCase):
def testMultiplication(self):
five = Money.dollar(5)
self.assertEqual(Money.dollar(10), five.times(2))
self.assertEqual(Money.dollar(15), five.times(3))
def testEquality(self):
self.assertTrue(Money.dollar(5) == Money.dollar(5))
self.assertFalse(Money.dollar(5) == Money.dollar(6))
self.assertFalse(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.plus(five)
bank = Bank()
reduced = bank.reduce(_sum, "USD")
self.assertEqual(Money.dollar(10), reduced)
def testPlusReturnsSum(self):
five = Money.dollar(5)
_sum = five.plus(five)
self.assertEqual(five, _sum.augend)
self.assertEqual(five, _sum.addend)
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"))
def testMixedAddition(self):
fiveBucks = Money.dollar(5)
tenFrancs = Money.franc(10)
bank = Bank()
bank.add_rate("CHF", "USD", 2)
result = bank.reduce(fiveBucks.plus(tenFrancs), "USD")
self.assertEqual(Money.dollar(10), result)
def testSumPlusMoney(self):
fiveBucks = Money.dollar(5)
tenFrancs = Money.franc(10)
bank = Bank()
bank.add_rate("CHF", "USD", 2)
_sum = Sum(fiveBucks, tenFrancs).plus(fiveBucks)
result = bank.reduce(_sum, "USD")
self.assertEqual(Money.dollar(15), result)
def testSumTimes(self):
fiveBucks = Money.dollar(5)
tenFrancs = Money.franc(10)
bank = Bank()
bank.add_rate("CHF", "USD", 2)
_sum = Sum(fiveBucks, tenFrancs).times(2)
result = bank.reduce(_sum, "USD")
self.assertEqual(Money.dollar(20), result)
Nehmen Sie folgende Änderungen vor:
example/money.py
from example.expression import Expression
class Money(Expression):
def __init__(self, amount, currency):
self.__amount = amount
self.__currency = currency
def __eq__(self, other):
return (self.__amount == other.__amount
and self.currency() == other.currency())
def times(self, multiplier):
return Money(self.__amount * multiplier, self.__currency)
def plus(self, addend):
return Sum(self, addend)
def reduce(self, bank, toCurrency):
rate = bank.rate(self.__currency, toCurrency)
return Money(self.__amount / rate, toCurrency)
def amount(self):
return self.__amount
def currency(self):
return self.__currency
@classmethod
def dollar(cls, amount):
return Money(amount, "USD")
@classmethod
def franc(cls, amount):
return Money(amount, "CHF")
class Sum(Expression):
def __init__(self, augend, addend):
self.augend = augend
self.addend = addend
def reduce(self, bank, toCurrency):
amount = self.augend.reduce(bank, toCurrency).amount() + \
self.addend.reduce(bank, toCurrency).amount()
return Money(amount, toCurrency)
def plus(self, addend):
return Sum(self, addend)
def times(self, multiplier):
return Sum(self.augend.times(multiplier), self.addend.times(multiplier))
example/expression.py
from abc import ABCMeta, abstractmethod
class Expression(metaclass=ABCMeta):
@abstractmethod
def plus(self, addend):
pass
@abstractmethod
def reduce(self, bank, toCurrency):
pass
@abstractmethod
def times(self, multiplier):
pass
Die Tests waren erfolgreich und die Abdeckung ist im Allgemeinen gut.
$ pytest -v --cov=example
...(snip)
tests/test_money.py::MoneyTest::testCurrency PASSED [ 8%]
tests/test_money.py::MoneyTest::testEquality PASSED [ 16%]
tests/test_money.py::MoneyTest::testIdentityRate PASSED [ 25%]
tests/test_money.py::MoneyTest::testMixedAddition PASSED [ 33%]
tests/test_money.py::MoneyTest::testMultiplication PASSED [ 41%]
tests/test_money.py::MoneyTest::testPlusReturnsSum PASSED [ 50%]
tests/test_money.py::MoneyTest::testReduceMoney PASSED [ 58%]
tests/test_money.py::MoneyTest::testReduceMoneyDifferentCurrency PASSED [ 66%]
tests/test_money.py::MoneyTest::testReduceSum PASSED [ 75%]
tests/test_money.py::MoneyTest::testSimpleAddition PASSED [ 83%]
tests/test_money.py::MoneyTest::testSumPlusMoney PASSED [ 91%]
tests/test_money.py::MoneyTest::testSumTimes PASSED [100%]
...(snip)
---------- coverage: platform darwin, python 3.8.0-final-0 -----------
Name Stmts Miss Cover
-------------------------------------------
example/__init__.py 0 0 100%
example/bank.py 13 0 100%
example/expression.py 11 3 73%
example/money.py 35 0 100%
-------------------------------------------
TOTAL 59 3 95%
...(snip)
Mit dem oben Gesagten habe ich versucht, die Entwicklung der Python-Version von "multinationaler Währung" unter Verwendung von ** testgetriebener Entwicklung ** zu erleben.
Sie können die testgetriebene Entwicklung in Python auch in Teil II "xUnit" des Buches "Testgetriebene Entwicklung" erleben. Als ich es erlebte, bemerkte ich tatsächlich, dass ** testgetriebene Entwicklung ** ganz anders war als der Test, den ich mir vorgestellt hatte, und ich habe es völlig falsch verstanden. Dies ist ein Zitat aus Kapitel 32 des Buches "Learn TDD"! !!
Ironischerweise ist TDD keine Testtechnik (Cunninghams Vorschlag). TDD ist eine Analysetechnik, eine Entwurfstechnik und tatsächlich eine Technik, die alle Aktivitäten der Entwicklung strukturiert.
Anhang C, "Übersetzerkommentar: Die Gegenwart der testgetriebenen Entwicklung", half mir, TDD / BDD zu verstehen, und war eine großartige Lernerfahrung.
Recommended Posts