2015-01-19 10 views
6

I am non che parla della funzione Parameterizing a fixture che consente a un dispositivo di essere eseguito più volte per un set di parametri hardcoded.Un modo per passare i parametri in un dispositivo più semplice?

Ho un sacco di test che seguono uno schema simile:

httpcode = 401 # this is different per call 
message = 'some message' # this is different per call 
url = 'some url' # this is different per call 


mock_req = mock.MagicMock(spec_set=urllib2.Request) 
with mock.patch('package.module.urllib2.urlopen', autospec=True) as mock_urlopen, \ 
    mock.patch('package.module.urllib2.Request', autospec=True) as mock_request: 
    mock_request.return_value = mock_req 
    mock_urlopen.side_effect = urllib2.HTTPError(url, httpcode, message, {}, None) 
    connection = MyClass() 
    with pytest.raises(MyException): 
     connection.some_function() # this changes 

In sostanza, ho una classe che è un client API, e comprende personalizzati, eccezioni significative che avvolgono urllib2 errori in qualcosa di specifico-API. Quindi, ho questo modello: l'applicazione di alcuni metodi e l'impostazione di effetti collaterali su uno di essi. Lo uso probabilmente in una dozzina di test diversi e le uniche differenze sono le tre variabili utilizzate in parte di side_effect e il metodo di MyClass() che chiamo.

C'è un modo per rendere questo un dispositivo più facile e passare in queste variabili?

risposta

15

È possibile utilizzare indiretta apparecchio parametrizzazione http://pytest.org/latest/example/parametrize.html#deferring-the-setup-of-parametrized-resources

@pytest.fixture() 
def your_fixture(request): 
    httpcode, message, url = request.param 
    mock_req = mock.MagicMock(spec_set=urllib2.Request) 
    with mock.patch('package.module.urllib2.urlopen', autospec=True) as mock_urlopen, \ 
     mock.patch('package.module.urllib2.Request', autospec=True) as mock_request: 
     mock_request.return_value = mock_req 
     mock_urlopen.side_effect = urllib2.HTTPError(url, httpcode, message, {}, None) 
     connection = MyClass() 
     with pytest.raises(MyException): 
      connection.some_function() # this changes 


@pytest.mark.parametrize('your_fixture', [ 
    (403, 'some message', 'some url') 
], indirect=True) 
def test(your_fixture): 
    ... 

e your_fixture verrà eseguito prima della prova con params desiderati

+0

Ho detto in particolare che questo non è quello che voglio ... Non voglio che l'apparecchiatura venga creata più volte, voglio solo passarvi dei parametri. –

+1

Nella mia apparecchiatura del codice viene eseguita una sola volta nel test. In realtà il mio codice fa la stessa cosa del tuo. La differenza sta nel modo in cui i parametri vengono passati. Se vuoi generare parametri all'interno di test e poi passarli a fixture - il tuo codice è solo un modo per farlo. Se i parametri sono predefiniti nel test, allora il mio codice si adatta anche a –

+0

Ok, abbastanza equo. –

6

ho fatto un mazzo ulteriori ricerche su questo dal distacco la mia domanda, e la migliore Posso inventare:

Gli impianti non funzionano in questo modo. Basta usare una funzione regolare, vale a dire:

def my_fixture(httpcode, message, url): 
    mock_req = mock.MagicMock(spec_set=urllib2.Request) 
    with mock.patch('package.module.urllib2.urlopen', autospec=True) as mock_urlopen, \ 
     mock.patch('package.module.urllib2.Request', autospec=True) as mock_request: 
     mock_request.return_value = mock_req 
     mock_urlopen.side_effect = urllib2.HTTPError(url, httpcode, message, {}, None) 
     connection = MyClass() 
     return (connection, mock_request, mock_urlopen) 

def test_something(): 
    connection, mock_req, mock_urlopen = my_fixture(401, 'some message', 'some url') 
    with pytest.raises(MyException): 
     connection.some_function() # this changes 
1

So che questo è vecchio, ma forse aiuta qualcuno che inciampa su questo nuovo

@pytest.fixture 
def data_patcher(request): 

    def get_output_test_data(filename, as_of_date=None): 
     # a bunch of stuff to configure output 
     return output 

    def teardown(): 
     pass 

    request.addfinalizer(teardown) 

    return get_output_test_data 

e poi, all'interno della funzione:

with patch('function to patch', new=data_patcher): 
Problemi correlati