pytest: setup a mock for every test function

对着背影说爱祢 提交于 2020-04-17 21:32:51

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!