问题
Creating unit tests for a python project we're reaching this kind of 'template'
from unittest import TestCase
from unittest.mock import patch, Mock
@patch('......dependency1')
@patch('......dependency2')
@patch('......dependencyn')
class MyTest(TestCase):
def test_1(self, mock1, mock2, mockn):
# setup mock1 & mock2...
# call the subject case 1
# assert response and/or interactions with mock1 and mock2...
def test_2(self, mock1, mock2, mockn):
# setup mock1 & mock2...
# call the subject case 2
# assert response and/or interactions with mock1 and mock2...
The point is, sometimes the "setup" section is duplicated across some test cases, so what I'd like to extract configuration to the setUp()
method for example, the following is pseudo-code:
def setUp(self):
mock1.foo.return_value = 'xxx'
mock2.goo.side_effect = [ ... ]
def test_1(self, mock1, mock2, mockn):
# default setup is perfect for this test
def test_2(self, mock1, mock2, mockn):
# this time I need...
mock2.goo.side_effect = [ ... ]
Is it possible to achieve this idea?
回答1:
Both pytest
and unittest
offer the possibilities you are asking about, and for both the features are explained in the respective documentation with examples: Look for fixture
in the pytest
documentation and setup
in the unittest
documentation.
However, the use of these features in practice quickly gets out of hand and has the tendency to create unreadable test code. It takes two forms, one being that the shared fixture setup just becomes too big (too general), making it difficult for the reader to understand what is actually relevant for a particular test case. The second is, that the test code is no longer self contained and it seems that magic happens outside. Meszaros calls the resulting test smell 'Obscure Test' with the above scenarios called 'General Fixture' and 'Mystery Guest'.
My recommendation is, to prefer helper functions / methods, that you call explicitly from each test. You can have several of them, give them descriptive names and so keep your test code readable without requiring a reader first to search through the file to find any 'automagic' stuff. In your example the tests could then look like this:
def test_1(self, mock1, mock2, mockn):
default_setup(mock1, mock2, mockn)
# further test code...
def test_2(self, mock1, mock2, mockn):
default_setup(mock1, mock2, mockn)
setup_mock2_to_behave_as_xxx(mock2)
# further test code...
def test_3(self, mock1, mock2, mockn):
setup_mock1_to_always_xxx(mock1)
setup_mock2_to_behave_as_xxx(mock2)
setup_mockn_to_xxx(mockn)
# further test code...
来源:https://stackoverflow.com/questions/54924026/pytest-setup-a-mock-for-every-test-function