ValueError:<class'myapp.tests.sessiontestcase'=“”>中没有这样的测试方法:runTest </class>

时间:2010-01-19 01:29:47

标签: python unit-testing

我有一个测试用例:

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 个答案:

答案 0 :(得分:26)

与“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子类实例来模仿行为 - 只需提供name作为第一个参数:

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)

答案 1 :(得分:25)

这里有一些'深黑魔法':

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

如果您只想测试从shell运行单元测试(即IPython),那么非常方便。

答案 2 :(得分:8)

如果您不介意直接编辑单元测试模块代码,那么简单的修复是在 case.py TestCase 下添加一个名为runTest的新方法,该方法不执行任何操作

要编辑的文件位于pythoninstall \ Lib \ unittest \ case.py

def runTest(self):
    pass

这将阻止您收到此错误。

答案 3 :(得分:4)

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'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')])。因此,如果您想手动创建测试用例,则需要执行相同的操作。

答案 4 :(得分:4)

@ dmvianna的回答让我非常接近能够在jupyter(ipython)笔记本中运行unittest,但我不得不做更多。如果我写下以下内容:

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.000秒内进行0次测试

     

它没有坏掉,但它没有进行任何测试!如果我实例化了测试类

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

(请注意行尾的parens;这是唯一的变化)

        

ValueError Traceback(最近一次调用最后一次)    in()   ----&GT; 1 suite = unittest.TestLoader()。loadTestsFromModule(TestStringMethods())

      init 中的 /usr/lib/python2.7/unittest/case.pyc(self,methodName)       189除AttributeError外:       190提出ValueError(&#34;在%s中没有这样的测试方法:%s&#34;%    - &GT; 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)
        

以0.002秒进行3次测试

     

如果我的runTest只是pass,它也能正常运行(并运行3次测试),正如@Darren所建议的那样。

这是一个小小的yucchy,我需要一些手工劳动,但它也更明确,这是一种Python的美德,不是吗?

我无法通过使用此处的显式参数调用unittest.main或从相关问题Unable to run unittest's main function in ipython/jupyter notebook调用jupyter笔记本中的任何技术,但是我回到了路上燃气罐。

答案 5 :(得分:-7)

unittest做深黑魔术 - 如果你选择用它来运行你的单元测试(我这样做,因为这样我可以使用非常强大的测试跑步者电池并集成到构建中我的工作场所的系统,但肯定有价值的替代方案),你最好遵守它的规则。

在这种情况下,我只是EditProfileTestCase来自LoginTestCase(而不是直接来自unittest.TestCase)。如果LoginTestCase的某些部分确实要在EditProfileTestCase的不同环境中进行测试,而其他部分则不在LoginTestCase进行测试,那么将{{1}}重构为这些部分是一件简单的事情。两个部分(可能使用多重继承)如果某些事情需要在两种情况下略有不同,将它们分解为辅助“钩子方法”(在“模板方法”设计模式中) - 我经常使用所有这些方法在我总是写的大量单元测试中减少样板并增加重复使用(如果我有单位测试覆盖率<95%,我总是感到非常不安 - 低于90%,我开始感到身体不适; - )。