ValueError: нет такого метода тестирования в <class 'myapp.tests.SessionTestCase'>: runTest
У меня есть тестовый пример:
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
как сомнительный обходной путь.
Ответы
Ответ 1
unittest
делает глубокую черную магию - если вы решите использовать ее для запуска ваших юнит-тестов (я это делаю, так как я могу использовать очень мощную батарею тестовых бегунов и интеграторов в систему сборки на мое рабочее место, но есть определенные альтернативы), вам лучше играть по своим правилам.
В этом случае я бы просто получил EditProfileTestCase
из LoginTestCase
(а не непосредственно из unittest.TestCase
). Если есть некоторые части LoginTestCase
, которые вы также хотите протестировать в другой среде EditProfileTestCase
, а другие, которые у вас нет, просто реорганизуйте LoginTestCase
в эти две части (возможно, используя несколько наследование), и если в двух случаях некоторые вещи должны произойти немного по-разному, выставляйте их во вспомогательные "методы крюка" (в шаблоне проектирования "Шаблонный метод" ) - я часто использую все эти подходы, чтобы уменьшить шаблон и увеличить повторное использование в сложных анализах я всегда пишу (если у меня есть модульное тестирование и <95%, я всегда чувствую себя действительно непросто - ниже 90%, я начинаю чувствовать физически больным; -).
Ответ 2
Путаница с "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)
Ответ 3
Здесь некоторая ' глубокая черная магия':
suite = unittest.TestLoader().loadTestsFromTestCase(Test_MyTests)
unittest.TextTestRunner(verbosity=3).run(suite)
Очень удобно, если вы просто хотите протестировать запуск своих модульных тестов из оболочки (т.е. IPython).
Ответ 4
Если вы не возражаете редактировать код модуля unit test напрямую, простое исправление заключается в том, чтобы добавить в case.py класс TestCase новый метод под названием runTest, который делает ничего.
Файл для редактирования находится под pythoninstall\Lib\unittest\case.py
def runTest(self):
pass
Это остановит вас при получении этой ошибки.
Ответ 5
Ответ Guido почти есть, но это не объясняет. Мне нужно было посмотреть код 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 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')])
. Поэтому, если вы хотите создать тестовый пример вручную, вам нужно сделать то же самое.
Ответ 6
@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)
Я получил
Ran 0 тестов в 0.000s
OK
Он не сломан, но он не запускает никаких тестов! Если я создал экземпляр класса
suite = unittest.TestLoader().loadTestsFromModule (TestStringMethods())
(обратите внимание на parens в конце строки, что единственное изменение) я получил
Traceback ValueError (последний последний вызов) в() ---- > 1 suite = unittest.TestLoader(). LoadTestsFromModule (TestStringMethods())
/usr/lib/python2.7/unittest/case.pyc в init (self, methodName) 189 кроме AttributeError: 190 повышают значение ValueError ( "нет такого метода теста в% s:% s" % → 191 (self. класс, 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)
Ran 3 тесты в 0.002s
OK
Он также работает правильно (и запускает 3 теста), если мой runTest
просто pass
es, как было предложено @Darren.
Это немного суетливый, требующий ручного труда с моей стороны, но он также более явный, и что добродетель Питона, не так ли?
Я не смог получить какие-либо из этих методов, вызвав unittest.main
с явными аргументами отсюда или из этого связанного вопроса Невозможно запустить основную функцию unittest в ноутбуке ipython/jupyter работать внутри ноутбука jupyter, но я снова на дороге с полным баком газа.