Immaginate di aver implementato un programma di utilità (forse una classe) chiamato Bar
in un modulo foo
, e ho scritto i seguenti test per questo.pytest: test riutilizzabili per diverse implementazioni della stessa interfaccia
test_foo.py:
from foo import Bar as Implementation
from pytest import mark
@mark.parametrize(<args>, <test data set 1>)
def test_one(<args>):
<do something with Implementation and args>
@mark.parametrize(<args>, <test data set 2>)
def test_two(<args>):
<do something else with Implementation and args>
<more such tests>
Ora immaginate che, in futuro, mi aspetto diverse implementazioni della stessa interfaccia da scrivere. Vorrei quelle implementazioni per essere in grado di riutilizzare i test che sono stati scritti per la suite di test di cui sopra: le uniche cose che hanno bisogno di cambiare sono
- L'importazione del
Implementation
<test data set 1>
,<test data set 2>
ecc
Quindi sto cercando un modo per scrivere i test di cui sopra in modo riutilizzabile, che consentirebbe agli autori di nuove implementazioni dell'interfaccia di essere in grado di utilizzare i test iniettando l'implementazione e i dati di test in essi, senza dover modificare il file contenente le specifiche originali dei test.
Quale sarebbe un buon modo idiomatico di farlo in pytest?
========================================= ======================
======================== ==============================
Qui è una versione unittest che (non è carina ma) funziona.
define_tests.py:
# Single, reusable definition of tests for the interface. Authors of
# new implementations of the interface merely have to provide the test
# data, as class attributes of a class which inherits
# unittest.TestCase AND this class.
class TheTests():
def test_foo(self):
# Faking pytest.mark.parametrize by looping
for args, in_, out in self.test_foo_data:
self.assertEqual(self.Implementation(*args).foo(in_),
out)
def test_bar(self):
# Faking pytest.mark.parametrize by looping
for args, in_, out in self.test_bar_data:
self.assertEqual(self.Implementation(*args).bar(in_),
out)
v1.py:
# One implementation of the interface
class Implementation:
def __init__(self, a,b):
self.n = a+b
def foo(self, n):
return self.n + n
def bar(self, n):
return self.n - n
v1_test.py:
# Test for one implementation of the interface
from v1 import Implementation
from define_tests import TheTests
from unittest import TestCase
# Hook into testing framework by inheriting unittest.TestCase and reuse
# the tests which *each and every* implementation of the interface must
# pass, by inheritance from define_tests.TheTests
class FooTests(TestCase, TheTests):
Implementation = Implementation
test_foo_data = (((1,2), 3, 6),
((4,5), 6, 15))
test_bar_data = (((1,2), 3, 0),
((4,5), 6, 3))
Chiunque (anche un cliente della biblioteca) scrivendo un'altra implementazione di questa interfaccia
- può riutilizzare il set di test definiti
define_tests.py
- iniettare propri dati di test nelle prove
- senza modificare qualsiasi file originali
Come questo consentirà di nuove implementazioni gli autori di aggiungere nuove parametrizzazioni dei test senza toccare i file originali contenenti le definizioni del test? – jacg
È possibile spostare la definizione del dispositivo in un punto centrale, un file conftest.py a un livello superiore. La documentazione è qui: http://pytest.org/latest/fixture.html#sharing-a-fixture-across-tests-in-a-module-or-class-session Vuoi mantenere nuovi autori da toccare alcuni file di test in particolare o qualcosa nella suite di test? –
Dovrebbe essere possibile aggiungere estensioni senza modificare * qualsiasi * codice esistente. Se spedisco una libreria con alcune implementazioni conformi e i relativi test, i client della libreria dovrebbero essere in grado di aggiungere nuove implementazioni * e i loro test * senza modificare * qualsiasi * dei file forniti con la libreria. Questo sarebbe banale, se non fosse per il fatto che voglio riutilizzare i test exsting inserendo nuovi dati in essi. Spostando l'apparecchio in un conftest.py che viene fornito con la libreria, si richiederebbe (a meno che non mi sia sfuggito qualcosa) l'estensione per modificare un file fornito con la libreria. – jacg