Как мне заглушить класс в модуле в Python для тестирования? - PullRequest
3 голосов
/ 29 сентября 2011

У меня есть модуль, который я использую, который использует RealClass, поэтому это внутренняя зависимость, к которой у меня нет доступа.

Я хочу иметь возможность создать FakeClass, который заменяет функциональность RealClass для тестирования. Я не хочу заменять отдельные методы, но весь класс.

Я посмотрел на щетину , которая, кажется, то, что я хочу, но мне было интересно, если mox или какие-либо другие фреймворки имеют эту функцию? Или что бы вы предложили использовать? Может быть выдумка , мартышка-патчинг? Просто ищу лучшие практики с этим материалом. Также были бы полезны любые полезные примеры.

Псевдокод:

from module import RealClass

class FakeClass
    methodsFromRealClassOverridden

class Test(unittest.TestCase):
    setup()
    teardown()

test1()
    stub(RealClass, FakeClass) // something like this, but really just want the functionality
    classThatUsesRealClass // now will use FakeClass

UPDATE

Вот один способ, которым я нашел это сделать. Это не идеально, но работает.

Пример:

fake = FakeClass()
stub = stubout.StubOutForTesting()
stub.Set(RealClass, 'method_1', fake.method_1)
stub.Set(RealClass, 'method_2', fake.method_2)

1 Ответ

6 голосов
/ 02 октября 2011

Я думаю, вам нужны мнения / опыт, поэтому я просто даю свои 2 цента.

Как вы заметили, есть несколько инструментов / классов / инфраструктур тестирования Python, но большую часть времени, учитывая простоту / динамичность / открытость Python, вы ограничитесь использованием специальных тестовых случаев, связанных с заглушкой интерфейса. уровень, и немного unittest ... пока вы не начнете использовать рамки.

Нет ничего уничижительного в исправлении обезьян, особенно когда речь идет о выполнении тестирования / заглушки:

#!/usr/bin/env python
# minimal example of library code

class Class:
    """ a class """
    def method(self, arg):
        """ a method that does real work """
        print("pouet %s" % arg)

#!/usr/bin/env python
# minimal example for stub and tests, overriding/wrapping one method
from Class import Class

Class._real_method = Class.method
def mymethod(self, arg):
    # do what you want
    print("called stub")
    # in case you want to call the real function...
    self._real_method(arg)
Class.method = mymethod

# ...

e = Class()
e.method("pouet")

Пространства имен позволят вам исправлять вещи внутри импортированных модулей внутри импортированных модулей ...

Обратите внимание, что приведенный выше метод не работает с классами в модулях C. Для них вы можете использовать класс-оболочку, который фильтрует имена членов класса с помощью getattr / setattr и возвращает переопределенные члены из класса-оболочки.

#!/usr/bin/env python
# Stupid minimal example replacing the sys module
# (not very useful / optimal, it's just an example of patching)

import sys

class SysWrap():
    real = sys
    def __getattr__(self, attr):
        if attr == 'stderr':
            class StdErr():
                def write(self, txt):
                    print("[err: %s]" % txt)
            return StdErr()
        print("Getattr %s" % attr)
        return getattr(SysWrap.real, attr)

sys = SysWrap()
# use the real stdout
sys.stdout.write("pouet")
# use fake stderr
sys.stderr.write("pouet")

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

Вероятно, что часть специального исправления обезьян останется, это просто понять, и все инструменты имеют некоторые ограничения.

Инструменты дают вам силы, но вы должны глубоко понимать их, чтобы эффективно их использовать.

Важным аспектом при принятии решения о том, использовать ли инструмент или нет, является то, что при передаче фрагмента кода вы передаете всю среду (включая инструменты тестирования). Следующий парень может быть не таким умным, как вы, и пропустить тестирование, потому что ваш инструмент тестирования слишком сложен для него. Как правило, вы хотите избежать использования большого количества зависимостей в вашем программном обеспечении.

В конце концов, я думаю, что никто не побеспокоит вас, если вы просто используете unittest и специальные тесты / monkey-patching, если ваши вещи работают. Ваш код может не быть таким сложным.

...