Sie haben Recht, Ihre Tests sollten nicht bestätigen, dass das random
Modul seine Aufgabe erfüllt. Ein Unittest sollte nur die Klasse selbst testen, nicht die Interaktion mit anderem Code (der separat getestet werden sollte).
Es ist natürlich durchaus möglich, dass Ihr Code random.randint()
falsch verwendet; oder du callst random.randrange(1, self._sides)
stattdessen und dein Würfel wirft nie den höchsten Wert, aber das wäre eine andere Art von Bug, die du nicht mit einem Unittest fangen könntest. In diesem Fall funktioniert Ihr die
Gerät wie geplant, aber das Design selbst war fehlerhaft.
In diesem Fall würde ich die Funktion durch Verspotten ersetzenrandint()
und nur überprüfen, ob sie korrekt aufgerufen wurde . Python 3.3 und höher enthält das unittest.mock
Modul für diese Art von Tests. Sie können das externe mock
Paket jedoch auch auf älteren Versionen installieren , um genau die gleiche Funktionalität zu erhalten
import unittest
try:
from unittest.mock import patch
except ImportError:
# < python 3.3
from mock import patch
@patch('random.randint', return_value=3)
class TestDice(unittest.TestCase):
def _make_one(self, *args, **kw):
from die import Die
return Die(*args, **kw)
def test_standard_size(self, mocked_randint):
die = self._make_one()
result = die.roll()
mocked_randint.assert_called_with(1, 6)
self.assertEqual(result, 3)
def test_custom_size(self, mocked_randint):
die = self._make_one(sides=42)
result = die.roll()
mocked_randint.assert_called_with(1, 42)
self.assertEqual(result, 3)
if __name__ == '__main__':
unittest.main()
Mit dem Verspotten ist Ihr Test jetzt sehr einfach; es gibt eigentlich nur 2 fälle. Der Standardfall für einen 6-seitigen Würfel und der benutzerdefinierte Seitenfall.
Es gibt andere Möglichkeiten, die randint()
Funktion im globalen Namespace von vorübergehend zu ersetzen Die
, aber das mock
Modul macht dies am einfachsten. Der @mock.patch
Dekorateur gilt hier für alle Testmethoden im Testfall; Jeder Testmethode wird ein zusätzliches Argument übergeben, die verspottete random.randint()
Funktion, damit wir anhand der Verspottung testen können, ob sie tatsächlich korrekt aufgerufen wurde. Das return_value
Argument gibt an, was vom Mock zurückgegeben wird, wenn es aufgerufen wird, sodass wir überprüfen können, ob die die.roll()
Methode tatsächlich das "zufällige" Ergebnis an uns zurückgegeben hat.
Ich habe hier eine andere, nicht zu testende, bewährte Methode von Python verwendet: Importieren Sie die zu testende Klasse als Teil des Tests. Das _make_one
Verfahren hat den Import und Instanziierung Arbeit in einem Test , so dass das Testmodul noch selbst wird geladen , wenn Sie einen Syntaxfehler oder andere Fehler gemacht, die das ursprüngliche Modul Import verhindern werde.
Wenn Sie auf diese Weise einen Fehler im Modulcode selbst gemacht haben, werden die Tests weiterhin ausgeführt. Sie werden nur scheitern und Sie über den Fehler in Ihrem Code informieren.
Die obigen Tests sind im Extremfall einfach. Das Ziel ist hier nicht zu testen random.randint()
, was zum Beispiel mit den richtigen Argumenten aufgerufen wurde. Stattdessen soll getestet werden, ob das Gerät bei bestimmten Eingaben die richtigen Ergebnisse liefert, wobei diese Eingaben die Ergebnisse anderer nicht getesteter Geräte einschließen . Durch das Verspotten der random.randint()
Methode können Sie nur eine weitere Eingabe in Ihren Code steuern.
In realen Tests wird der tatsächliche Code in Ihrem zu testenden Gerät komplexer. Die Beziehung zu Eingaben, die an die API übergeben werden, und wie andere Einheiten dann aufgerufen werden, kann immer noch interessant sein. Durch das Verspotten erhalten Sie Zugriff auf Zwischenergebnisse und können die Rückgabewerte für diese Aufrufe festlegen.
In Code, der Benutzer für einen OAuth2-Dienst eines Drittanbieters authentifiziert (eine mehrstufige Interaktion), möchten Sie beispielsweise testen, ob Ihr Code die richtigen Daten an diesen Dienst eines Drittanbieters weiterleitet, und Sie können verschiedene Fehlerantworten ausspotten Der Dienst eines Drittanbieters würde zurückkehren und Sie könnten verschiedene Szenarien simulieren, ohne selbst einen vollständigen OAuth2-Server erstellen zu müssen. Hier ist es wichtig zu testen, ob die Informationen aus einer ersten Antwort korrekt verarbeitet und an einen zweiten Aufruf weitergeleitet wurden. Sie möchten also sicherstellen, dass der gespielte Dienst korrekt aufgerufen wird.