Как дополнить класс из внешней библиотеки собственными методами? - PullRequest
2 голосов
/ 06 сентября 2011

У меня есть несколько особых случаев, которые мне нужно проверить в django.Я пытаюсь расширить существующие тесты django, написав свои собственные контрольные примеры.Вот как я это делаю в настоящее время.

from django.tests import TestCase

# define my own method as a function
def assertOptionsEqual(self, first, second):
    # logic here
    pass

# Attach the method to the TestCase class. This feels inelegant!
TestCase.assertOptionsEqual = assertOptionsEqual

# tests go here
class KnownGoodInputs(TestCase):
    def test_good_options(self):
        self.assertOptionsEqual(...)

Хотя это работает, определение метода как функции с self в качестве первого параметра и последующее присоединение его к TestCase выглядит неуверенным.Есть ли лучший способ дополнить класс TestCase моими собственными методами?Я могу сделать это ...

class MyTestCase(TestCase):
    def assertOptionsEqual(self, first, second):
        ...

и использовать MyTestCase для всех тестов, но мне было интересно, есть ли лучшая альтернатива.Спасибо!

1 Ответ

1 голос
/ 06 сентября 2011

Я думаю, что вы рассмотрели оба варианта.Вы можете подкласс или monkeypatch.Как правило, применение обезьяньего патча, фактически изменение стороннего класса во время выполнения, не одобряется, но в зависимости от того, какие изменения вам нужно внести, это может быть единственным способом обойти ошибку или убедиться, что каждый раз, когда этот класс используется, у него есть новый метод..

Поскольку единственными тестами, в которых используется ваш метод, будет , то ваши тесты monkeypatching не нужны, и вполне разумно подкласс TestCase.Как правило, вы используете monkeypatching, когда вам нужно расширить метод существующего класса.Например, если вы хотите, чтобы вызовы TestCase.assertEqual в ваших существующих тестовых примерах были дополнены логикой для сравнения с Option объектами, вы могли бы monkeypatch TestCase.assertEqual включить вашу пользовательскую логику плюс ее обычную логику, выполнив что-то вроде:

originalAssertEqual = TestCase.assertEqual
def newAssertEqual(self, first, second):
    result = originalAssertEqual(first, second)
    if isinstance(first, Option) and isinstance(second, Option):
        # do your custom comparison
    return result
TestCase.assertEqual = newAssertEqual 

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

Предполагается, что проблема в том, что вызов self.assertEqual(firstOptions, secondOptions) завершается неудачно, даже если экземпляры Optionравно вам не нужно писать новый assertOptionsEqual метод.Вам, вероятно, просто нужны ваши объекты Option, чтобы правильно определить __eq__.

При условии, что вы получили:

class KnownGoodInputs(TestCase):
    def test_good_options(self):
        first, second = systemUnderTestGetOptions(...)
        self.assertOptionsEqual(first, second)

Какие классы first и second выше?

Для всех встроенных типов Python assertEqual должно работать.Для пользовательского Option класса просто сделайте что-то вроде этого:

class Опция (объект): def init (self): use_foo = False use_bar = True

def __eq__(self, other):
    if (self.use_foo == other.use_foo and
        self.use_bar == other.use_bar):
        return True
    return False

Тогда, предполагая, что first и second являются экземплярами Option, вы можете написать свой тест так же, как:

class KnownGoodInputs(TestCase):
    def test_good_options(self):
        first, second = systemUnderTestGetOptions(...)
        self.assertEqual(first, second)
...