ValueError: такого метода тестирования в <class 'myapp.tests.SessionTestCase'> нет: runTest - PullRequest
19 голосов
/ 19 января 2010

У меня есть тестовый пример:

class LoginTestCase(unittest.TestCase):
    ...

Я хотел бы использовать его в другом тестовом примере:

class EditProfileTestCase(unittest.TestCase):
  def __init__(self):
    self.t = LoginTestCase()
    self.t.login()

Это повышает:

ValueError: no such test method in <class 'LoginTest: runTest`

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

Я добавил пустой runTest метод к LoginTest в качестве сомнительного обходного пути.

Ответы [ 6 ]

26 голосов
/ 25 апреля 2013

Путаница с "runTest" в основном основана на том факте, что это работает:

class MyTest(unittest.TestCase):
    def test_001(self):
        print "ok"

if __name__ == "__main__":
    unittest.main()

Таким образом, в этом классе нет runTest, и все тестовые функции вызываются. Однако, если вы посмотрите на базовый класс «TestCase» (lib / python / unittest / case.py), то обнаружите, что у него есть аргумент «methodName», который по умолчанию равен «runTest», но он НЕ имеет реализацию по умолчанию «» def runTest "

class TestCase:
    def __init__(self, methodName='runTest'):

Причина, по которой unittest.main работает нормально, основана на том факте, что ему не нужен "runTest" - вы можете имитировать поведение, создав экземпляр TestCase-подкласса для всех методов, которые есть в вашем подклассе - просто укажите имя в качестве первого аргумента:

class MyTest(unittest.TestCase):
    def test_001(self):
        print "ok"

if __name__ == "__main__":
    suite = unittest.TestSuite()
    for method in dir(MyTest):
       if method.startswith("test"):
          suite.addTest(MyTest(method))
    unittest.TextTestRunner().run(suite)
25 голосов
/ 13 ноября 2014

Вот немного ' глубокой черной магии ':

suite = unittest.TestLoader().loadTestsFromTestCase(Test_MyTests)
unittest.TextTestRunner(verbosity=3).run(suite)

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

8 голосов
/ 19 февраля 2015

Если вы не возражаете редактировать код модуля модульного тестирования напрямую, простое исправление заключается в добавлении в case.py class TestCase нового метода с именем runTest, который ничего не делает.

Файл для редактирования находится в папке pythoninstall \ Lib \ unittest \ case.py

def runTest(self):
    pass

Это остановит вас когда-либо, получая эту ошибку.

4 голосов
/ 01 февраля 2017

@ От ответа dmvianna я очень приблизился к возможности запустить unittest в ноутбуке с jupyter (ipython), но мне пришлось сделать немного больше.Если бы я написал следующее:

class TestStringMethods(unittest.TestCase):

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())

    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hello', 'world'])
        # check that s.split fails when the separator is not a string
        with self.assertRaises(TypeError):
            s.split(2)

suite = unittest.TestLoader().loadTestsFromModule (TestStringMethods)
unittest.TextTestRunner().run(suite)

Я получил


Запустил 0 тестов за 0,000 с

OK

Он не сломан, но не запускает никаких тестов!Если я инстанцировал тестовый класс

suite = unittest.TestLoader().loadTestsFromModule (TestStringMethods())

(обратите внимание на символы в конце строки; это единственное изменение), я получил бы


ValueError Traceback (самый последнийпоследний вызов) in () ----> 1 suite = unittest.TestLoader (). loadTestsFromModule (TestStringMethods ())

/ usr / lib / python2.7 / unittest / case.pyc в init (self, methodName) 189 кроме AttributeError: 190 повысить ValueError («нет такого метода тестирования в% s:% s»% -> 191 (self. class , methodName)) 192 self._testMethodDoc = testMethod. doc 193 self._cleanups = []

ValueError: нет такого метода тестирования в: runTest

Исправление теперь достаточно понятно:добавьте runTest к классу теста:

class TestStringMethods(unittest.TestCase):

    def runTest(self):
        test_upper (self)
        test_isupper (self)
        test_split (self)

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())

    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hello', 'world'])
        # check that s.split fails when the separator is not a string
        with self.assertRaises(TypeError):
            s.split(2)

suite = unittest.TestLoader().loadTestsFromModule (TestStringMethods())
unittest.TextTestRunner().run(suite)

Выполнено 3 теста за 0,002 с

OK

Это также работает правильно(и запускает 3 теста), если мои runTest просто pass es, как предложено @ Darren.

Это немного глупо, требует от меня ручного труда, но это также больше бывшийplicit , и это достоинство Python, не так ли?

Я не смог получить ни одну из техник, вызвав unittest.main с явными аргументами отсюда или из этого связанного вопроса Невозможнозапустить основную функцию unittest в ноутбуке ipython / jupyter , чтобы работать в ноутбуке jupyter, но я снова в пути с полным баком газа.

4 голосов
/ 22 октября 2014

Ответ Гвидо почти готов, но ничего не объясняет. Мне нужно было посмотреть на unittest код, чтобы понять поток.

Скажем, у вас есть следующее.

import unittest

class MyTestCase(unittest.TestCase):

  def testA(self):
    pass

  def testB(self):
    pass

Когда вы используете unittest.main(), он попытается обнаружить тестовые случаи в текущем модуле. Важный код unittest.loader.TestLoader.loadTestsFromTestCase.

def loadTestsFromTestCase(self, testCaseClass):
  # ...

  # This will look in class' callable attributes that start 
  # with 'test',  and return their names sorted.
  testCaseNames = self.getTestCaseNames(testCaseClass)

  # If there's no test to run, look if the case has the default method.
  if not testCaseNames and hasattr(testCaseClass, 'runTest'):
    testCaseNames = ['runTest']

  # Create TestSuite instance having test case instance per test method.
  loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))

  return loaded_suite

Последнее делает преобразование класса тестового набора в набор тестов, который содержит экземпляры класса для каждого метода тестирования. То есть мой пример будет превращен в unittest.suite.TestSuite([MyTestCase('testA'), MyTestCase('testB')]). Поэтому, если вы хотите создать тестовый набор вручную, вам нужно сделать то же самое.

0 голосов
/ 19 января 2010

unittest совершает глубокую чёрную магию - если вы решите использовать её для запуска своих юнит-тестов (я так и делаю, так как таким образом я могу использовать очень мощную батарею бегунов-тестировщиков и т. Д., Интегрированную в систему сборки на моем рабочем месте) , но есть определенно стоящие альтернативы), лучше играть по его правилам.

В этом случае я бы просто получил EditProfileTestCase из LoginTestCase (а не напрямую из unittest.TestCase). Если есть некоторые части LoginTestCase, которые вы хотите протестировать в другой среде EditProfileTestCase, а другие - нет, просто провести рефакторинг LoginTestCase в эти две части (возможно, используя несколько наследование) и если некоторые вещи должны происходить немного по-разному в обоих случаях, выделите их во вспомогательные «методы ловушек» (в шаблоне проектирования «Шаблонный метод») - я часто использую все эти подходы, чтобы уменьшить пример и увеличить повторное использование в обильных модульных тестах я всегда пишу (если у меня охват модульным тестом <95%, я всегда чувствую себя действительно неловко - ниже 90%, я начинаю чувствовать себя физически больным; -). </p>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...