В Python, что такое хороший шаблон для отключения определенного кода во время модульных тестов?

В целом я хочу отключить как можно меньше код, и я хочу, чтобы он был явным: Я не хочу код, протестированный, чтобы решить, является ли это тестом или нет, я хочу, чтобы тест сказал, что код "эй, BTW, я выполняю модульный тест, может Вы не выполнять свой вызов к solr, вместо этого можете Вы засовывать то, что Вы отправили бы в solr в этом месте, таким образом, я могу проверить его". У меня есть свои идеи, но мне не нравится ни один из них, я надеюсь, что существует хороший pythonic способ сделать это.

10
задан guidoism 23 February 2010 в 20:04
поделиться

6 ответов

Используйте макет Майкла Фурда в своем модульном тесте, сделайте следующее:

from mock import Mock

class Person(object):
    def __init__(self, name):
        super(Person, self).__init__()
        self.name = name

    def say(self, str):
        print "%s says \"%s\"" % (self.name, str)


...

#In your unit test....
#create the class as normal
person = Person("Bob")
#now mock all of person's methods/attributes
person = Mock(spec=person)
#talkto is some function you are testing
talkTo(person)
#make sure the Person class's say method was called
self.assertTrue(person.say.called, "Person wasn't asked to talk")

#make sure the person said "Hello"
args = ("Hello")
keywargs = {}
self.assertEquals(person.say.call_args, (args, keywargs), "Person did not say hello")
5
ответ дан 3 December 2019 в 23:49
поделиться

Большая проблема, с которой я столкнулся, заключалась в механике внедрения зависимостей. Теперь я понял эту часть.

Мне нужно импортировать модуль точно так же в обоих местах, чтобы успешно внедрить новый код. Например, если у меня есть следующий код, который я хочу отключить:

from foo_service.foo import solr
solr.add(spam)

Кажется, я не могу сделать это в моем тестовом средстве выполнения:

from foo import solr
solr = mock_object

Интерпретатор python должен обрабатывать модули foo_service.foo и foo как разные записи. Я изменил с foo import solr на более явный из foo_service.foo import solr , и мой фиктивный объект был успешно внедрен.

1
ответ дан 3 December 2019 в 23:49
поделиться

У вас есть два способа сделать это: нет или минимальный в случае DI , модификаций для ваш исходный код

Самый чистый способ использует инъекцию зависимостей , но я не очень люблю обширные monkeypatching , и есть некоторые вещи, которые невозможно / сложно сделать, что упрощает внедрение зависимостей .

0
ответ дан 3 December 2019 в 23:49
поделиться

Я знаю, что это типичный вариант использования имитирующих объектов, но это тоже старый аргумент ... нужны ли имитирующие объекты вообще или они зло ?

Я на стороне тех, кто считает, что насмешки зло , и стараюсь вообще избегать изменения проверяемого кода. Я даже считаю, что такая необходимость изменить проверенный код - это запах кода ...

Если вы хотите изменить или перехватить вызов внутренней функции для целей тестирования, вы также можете сделать эту функцию явной внешней зависимостью, установленной во время создания экземпляра, которая будет предоставляется как вашим производственным кодом, так и тестовым кодом. Если вы это сделаете, проблема исчезнет, ​​и вы получите более чистый интерфейс.

Обратите внимание, что при этом нет необходимости изменять тестируемый код ни внутри, ни во время выполнения теста.

0
ответ дан 3 December 2019 в 23:49
поделиться

Вы можете использовать Mock объекты для перехвата вызовов методов, которые вы не хотите выполнять. Например, у вас есть класс A, в котором вы не хотите, чтобы метод no() был вызван во время теста.

class A:
  def do(self):
    print('do')
  def no(self):
    print('no')

Макетный объект может наследоваться от A и переопределить no(), чтобы ничего не делать.

class MockA(A):
  def no(self):
    pass

Тогда в тестовом коде вы будете создавать объекты MockA вместо Aов. Другой способ мокинга заключается в том, что A и MockA реализуют общий интерфейс, скажем InterfaceA.

Существует множество фреймворков для мокинга. См. StackOverflow: Python mocking frameworks.

В частности, см: Google's Python mocking framework.

7
ответ дан 3 December 2019 в 23:49
поделиться

Обычно, когда возникает что-то подобное, вы используете Monkey Patching (также называемый Duck Punching) для достижения желаемых результатов. Просмотрите эту ссылку, чтобы узнать больше о "обезьяньей заделке".

В этом случае, например, вы перезапишете solr, чтобы он просто выводил нужный вам результат.

0
ответ дан 3 December 2019 в 23:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: