Как факторизовать тестовые случаи Python с помощью носовых тестов

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

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

class AbstractTest(TestCase):
  def test_empty(self):
      result = self.function(make_empty_graph())
      assertTrue(result....) # etc..
  def test_single_node(self):
      ...

Затем конкретные тестовые случаи

class TestF(AbstractTest):
  def setup(self):
      self.function = f
  def test_random(self):
      #specific test for algorithm 'f'

class TestG(AbstractTest):
  def setup(self):
      self.function = g
  def test_complete_graph(self):
      #specific test for algorithm 'g'

... И так далее для каждого алгоритма

К сожалению, Nosetests пытается выполнить каждый тест в AbstractTest, и это не работает, поскольку фактическая функция self.function указана в подклассах. Я попытался установить __test__ = False в случае AbstractTest, но в этом случае тест вообще не выполняется (поскольку это поле унаследовано, я полагаю). Я безуспешно пытался использовать абстрактный базовый класс (abc.ABCMeta). Я читал о MixIn без какого-либо результата (я не очень в нем уверен).

Я вполне уверен, что я не единственный, кто пытается факторизовать тестовый код. Как вы это делаете в Python?

Спасибо.


person pierre    schedule 21.02.2011    source источник


Ответы (1)


Nose собирает классы, соответствующие регулярному выражению или подклассы unittest.TestCase, поэтому самое простое решение - не делать ни того, ни другого:

class AlgoMixin(object):
  # Does not end in "Test"; not a subclass of unittest.TestCase.
  # You may prefer "AbstractBase" or something else.

  def test_empty(self):
    result = self.function(make_empty_graph())
    self.assertTrue(result)

class TestF(AlgoMixin, unittest.TestCase):
  function = staticmethod(f)
  # Doesn't need to be in setup, nor be an instance attribute.
  # But doesn't take either self or class parameter, so use staticmethod.

  def test_random(self):
    pass  # Specific test for algorithm 'f'.
person Fred Nurk    schedule 21.02.2011
comment
Спасибо! Оно работает. Однако я не понимаю, как вы можете удалить настройку «функции» в методе setUp(). Не работает: жалуется, что функция принимает только 1 аргумент, а задано 2 (self, make_empty_graph()). Поскольку функция определена в подклассе, я не понимаю, как я могу использовать ее в супервызове без использования себя. Есть идеи? Спасибо. - person pierre; 22.02.2011
comment
@pierre: Первая часть представляет собой довольно интересную часть того, как работают связанные методы, но краткий ответ - использовать статический метод. Тогда использование self.function работает. - person Fred Nurk; 22.02.2011
comment
статический метод работал для меня! Я понял! Вы правы, этот пример кажется прекрасной иллюстрацией разрешения методов Python. Спасибо. - person pierre; 24.02.2011