pytest: установить макет для каждой тестовой функции - PullRequest
0 голосов
/ 28 февраля 2019

При создании модульных тестов для проекта Python мы достигаем такого рода «шаблона»

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...

Дело в том, что иногда раздел «Настройка» дублируется в некоторых тестовых случаях, так что яЯ хотел бы извлечь конфигурацию для метода setUp(), например, псевдокод:

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 = [ ... ]

Возможно ли реализовать эту идею?

1 Ответ

0 голосов
/ 01 марта 2019

И pytest, и unittest предлагают возможности, о которых вы спрашиваете, и обе функции объясняются в соответствующей документации с примерами: ищите fixture в документации pytest и setup вunittest документация.

Однако использование этих функций на практике быстро выходит из-под контроля и имеет тенденцию создавать нечитаемый тестовый код.Он принимает две формы, одна из которых заключается в том, что настройка общего устройства становится слишком большой (слишком общей), что затрудняет читателю понимание того, что на самом деле актуально для конкретного тестового примера.Во-вторых, тестовый код больше не является самодостаточным, и кажется, что магия происходит снаружи.Meszaros называет результирующий запах теста «Obscure Test» с вышеупомянутыми сценариями, называемыми «General Fixture» и «Mystery Guest».

Моя рекомендация состоит в том, чтобы предпочесть вспомогательные функции / методы, которые вы вызываете явным образом из каждого теста.Вы можете иметь несколько из них, дать им описательные имена и, таким образом, сохранить свой тестовый код читабельным, не требуя от читателя предварительного поиска в файле, чтобы найти какие-либо «автоматические» вещи.В вашем примере тесты могут выглядеть следующим образом:

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...
...