Desidero testare il seguente metodo:
class MyClass(object):
...
def my_method(self, args):
... # Code which transforms args into arg1, arg2, ..., argN
self.A.other_method1(arg1, arg2)
self.A.other_method2(arg1, arg2, arg3)
self.A.other_method3(arg1)
self.B.other_method4(arg1, arg2)
self.B.other_method5(arg1, arg2, arg4)
self.B.other_method6(arg1, arg2, arg5, arg6)
Ovviamente questo è un esempio artificiale. Ho creato questo esempio per concentrarmi su quelli che ritengo siano i punti essenziali:
-
my_method
prima fa un lavoro semplice per trasformare i valori che è stato dato. Non mi interessa come testare questo aspetto. -
my_method
quindi chiama una sequenza di metodi su altri attributiA
eB
della classe. Non mi interessa come testare questi altri metodi. - La sequenza dei richiami di metodo cambia
A
eB
. Quindimy_method
è una funzione non pura. Non credo di poter riprogettare per rendere la funzione pura, poiché tutti gli altri metodi sono I / O.
Il mio attuale approccio consiste nel mettere alla prova A
e B
usando unittest.mock.MagicMock
, e poi asserire che questi metodi sono stati chiamati nell'ordine richiesto, con gli argomenti previsti. Il mio codice di test si presenta quindi come segue:
from unittest.mock import MagicMock, call
class MyTest(unittest.TestCase):
def test_MyClass_my_method(self):
x = MyClass() # Instantiation details omitted
x.A = MagicMock()
x.B = MagicMock()
x.my_method(0)
result_A = x.A.method_calls
result_B = x.B.method_calls
expected_result_A = [call.other_method1(1, 2),
call.other_method2(1, 2, 3),
call.other_method2(1)]
expected_result_B = [call.other_method4(1, 2),
call.other_method5(1, 2, 4),
call.other_method6(1, 2, 5, 6)]
self.assertEquals(result_A, expected_result_A)
self.assertEquals(result_B, expected_result_B)
Questo funziona. Ma non posso fare a meno di sentire che ho semplicemente riscritto my_method
- e, peggio, strettamente accoppiato il test al funzionamento interno del metodo.
C'è un modo migliore per testare questo metodo? Il metodo in realtà è mal progettato?