Questo non è senza avvertimenti e limitazioni, che è il motivo per cui è non il comportamento predefinito. Per sapere quali attributi sono disponibili su sull'oggetto spec, autospec deve analizzare (accedere agli attributi ) le specifiche. Mentre si attraversano gli attributi sulla simulazione, una traversata corrispondente dell'oggetto originale sta avvenendo sotto il cofano . Se uno qualsiasi degli oggetti specificati dispone di proprietà o descrittori che possono attivare l'esecuzione del codice, potrebbe non essere possibile utilizzare autospec. D'altra parte è molto meglio progettare gli oggetti in modo che l'introspezione sia sicura [4].
Un problema più serio è che è comune ad esempio attribuisce essere creato nella init metodo e non esiste sulla classe a tutto. autospec non può conoscere alcuno degli attributi creati dinamicamente e limita l'api agli attributi visibili.
penso che il takeaway chiave qui è da notare questa linea: Autospec non può sapere su eventuali attributi creati dinamicamente e limita l'API per attributi visibili
Quindi, a meno di essere più esplicito con una esempio di pause in cui autospeccing, questo esempio tratto dalla documentazione mostra questo:
>>> class Something:
... def __init__(self):
... self.a = 33
...
>>> with patch('__main__.Something', autospec=True):
... thing = Something()
... thing.a
...
Traceback (most recent call last):
...
AttributeError: Mock object has no attribute 'a'
Come si può vedere, autospeccing non ha idea che ci sia un attributo a
in fase di creazione durante la creazione del Something
oggetto.
In genere, per me stesso, ho appena preso in giro la patch e non uso molto l'autospec, poiché il comportamento è in genere in linea con le mie aspettative.
Non c'è niente di sbagliato nell'assegnare un valore all'attributo di istanza.
Osservare l'esempio seguente funzionale:
import unittest
from mock import patch
def some_external_thing():
pass
def something(x):
return x
class MyRealClass:
def __init__(self):
self.a = some_external_thing()
def test_thing(self):
return something(self.a)
class MyTest(unittest.TestCase):
def setUp(self):
self.my_obj = MyRealClass()
@patch('__main__.some_external_thing')
@patch('__main__.something')
def test_my_things(self, mock_something, mock_some_external_thing):
mock_some_external_thing.return_value = "there be dragons"
self.my_obj.a = mock_some_external_thing.return_value
self.my_obj.test_thing()
mock_something.assert_called_once_with("there be dragons")
if __name__ == '__main__':
unittest.main()
Così, sto solo dicendo per il mio banco di prova che voglio fare in modo che il metodo some_external_thing()
non influisce sul comportamento del mio unittest, quindi sono semplicemente assegnando il mio attributo di istanza al mockage per mock_some_external_thing.return_value = "there be dragons"
.