【问题标题】:ValueError: no such test method in <class 'myapp.tests.SessionTestCase'>: runTestValueError:在 <class 'myapp.tests.SessionTestCase'> 中没有这样的测试方法:runTest
【发布时间】:2010-01-19 01:29:46
【问题描述】:

我有一个测试用例:

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`

我查看了调用异常的单元测试代码,看起来测试不应该以这种方式编写。有没有一种标准的方法来编写你想要测试的东西,以便以后的测试可以重用它?或者有什么解决方法?

我已经向 LoginTest 添加了一个空的 runTest 方法,作为一个可疑的解决方法。

【问题讨论】:

    标签: python unit-testing


    【解决方案1】:

    与“runTest”的混淆主要是基于这样的事实:

    class MyTest(unittest.TestCase):
        def test_001(self):
            print "ok"
    
    if __name__ == "__main__":
        unittest.main()
    

    因此,该类中没有“runTest”,并且正在调用所有测试函数。但是,如果您查看基类“TestCase”(lib/python/unittest/case.py),您会发现它有一个默认为“runTest”的参数“methodName”,但它没有“ 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)
    

    【讨论】:

    • 您可能需要检查以确保method 确实是for 循环内的一个函数,test_name="foo" 之类的属性在这里可能是误报
    【解决方案2】:

    这里有一些“深奥的黑魔法”:

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

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

    【讨论】:

    • 除此之外,这就是我遇到的问题的实际解决方案!不知道为什么它是“在这里”而不是顶部!谢谢
    【解决方案3】:

    如果您不介意直接编辑单元测试模块代码,简单的解决方法是在 case.pyTestCase 下添加一个名为 runTest 的新方法,它什么都不做.

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

    def runTest(self):
        pass
    

    这将阻止您收到此错误。

    【讨论】:

    • 这也可以通过将这些代码行直接添加到您的 unittest.TestCase 子类中来实现
    【解决方案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
    

    后者所做的是将测试用例类转换为测试套件,该套件根据其测试方法保存类的实例。 IE。我的例子将变成unittest.suite.TestSuite([MyTestCase('testA'), MyTestCase('testB')])。所以如果你想手动创建一个测试用例,你需要做同样的事情。

    【讨论】:

      【解决方案5】:

      @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())
      

      (注意行尾的括号;这是唯一的变化)我得到了


      ValueError Traceback(最近一次调用最后一次) 在 () ----> 1 个套件 = unittest.TestLoader().loadTestsFromModule (TestStringMethods())

      /usr/lib/python2.7/unittest/case.pyc in init(self, methodName) 189 除了属性错误: 190 raise ValueError("在 %s 中没有这样的测试方法: %s" % --> 191 (self.class, methodName)) 192 self._testMethodDoc = testMethod.文档 193 自我._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 次测试

      好的

      按照@Darren 的建议,如果我的runTest 只是passes,它也可以正常工作(并运行3 个测试)。

      这有点麻烦,我需要一些体力劳动,但也更明确,这是 Python 的优点,不是吗?

      我无法通过调用unittest.main 并从这里或从这个相关问题Unable to run unittest's main function in ipython/jupyter notebook 中获得任何技术来在jupyter 笔记本中工作,但我带着满满一罐油回到了路上。

      【讨论】:

      • runTest 方法中,您的意思是说self.test_upper() 而不是test_upper(self)
      【解决方案6】:

      unittest 有很深的黑魔法——如果你选择用它来运行你的单元测试(我会这样做,因为这样我可以在我的工作场所使用集成到构建系统中的非常强大的测试运行器电池,但绝对有值得的替代品),你最好遵守它的规则。

      在这种情况下,我只需让 EditProfileTestCase 派生自 LoginTestCase(而不是直接派生自 unittest.TestCase)。如果您确实希望在EditProfileTestCase 的不同环境中测试LoginTestCase 的某些部分,而您不想在其他环境中测试,则将LoginTestCase 重构为这两个部分是一件简单的事情(可能使用多个继承),如果在这两种情况下某些事情需要稍微不同,请将它们分解为辅助的“挂钩方法”(在“模板方法”设计模式中)——我经常使用所有这些方法来减少样板文件并增加重用在我经常编写的大量单元测试中(如果我的单元测试覆盖率

      【讨论】:

      • 它是如何回答这个问题的?他问过良好报道的美德吗?为什么不讲讲如何“按规矩办事”呢?真的是“深层黑魔法”!?
      • 向下滚动,这是迄今为止最没用的答案。
      猜你喜欢
      • 2014-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多