2015-01-19 8 views
6

Ich bin nicht sprechen über die Parameterizing a fixture-Funktion, die eine Vorrichtung für einen fest codierten Satz von Parametern mehrmals ausgeführt werden kann.Eine Möglichkeit, Parameter in Pytest Fixture zu übergeben?

Ich habe eine Menge von Tests, die ein Muster wie folgt:

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 

Im Grunde habe ich eine Klasse, die eine API-Client ist, und umfasst kundenspezifische, sinnvolle Ausnahmen, die urllib2 Fehler in etwas API-spezifische wickeln. Also, ich habe dieses eine Muster - patchen einige Methoden und setzen Nebenwirkungen auf eine von ihnen. Ich verwende es in wahrscheinlich einem Dutzend verschiedener Tests, und die einzigen Unterschiede sind die drei Variablen, die in einem Teil des side_effect verwendet werden, und die Methode von MyClass(), die ich anrufe.

Gibt es eine Möglichkeit, dies zu einem pytest Fixture machen und diese Variablen übergeben?

Antwort

15

können Sie verwenden indirekte Befestigung Parametrisierung 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): 
    ... 

und your_fixture wird mit dem gewünschten params vor dem Test läuft

+0

Ich sagte ausdrücklich, dass dies nicht das ist, was ich will ... Ich möchte nicht, dass das Fixture mehrfach erstellt wird, ich möchte nur Parameter in das Fixture einbringen. –

+1

In meinem Code Fixture läuft nur einmal im Test. Tatsächlich macht mein Code das gleiche wie deines. Der Unterschied besteht in der Art und Weise, in der Parameter übergeben werden. Wenn Sie Parameter innerhalb des Tests generieren und sie dann an die Fixture übergeben möchten, ist Ihr Code nur eine Möglichkeit, dies zu tun. Wenn Parameter im Test vordefiniert sind, dann passt mein Code auch –

+0

Ok, fair genug. –

6

ich meine Frage ein paar mehr Forschung auf diesem seit der Veröffentlichung gemacht habe, und die besten Ich kann kommen ist:

Fixtures funktionieren nicht so. Verwenden Sie einfach eine reguläre Funktion, das heißt:

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

Ich weiß, das ist alt, aber vielleicht hilft es jemanden, der wieder

@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 

auf diese stolpert und dann innerhalb der Funktion:

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