python ValueError:<class 'myapp.tests.SessionTestCase'> 中没有这样的测试方法:runTest

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2090479/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 23:45:20  来源:igfitidea点击:

ValueError: no such test method in <class 'myapp.tests.SessionTestCase'>: runTest

pythonunit-testing

提问by Paul Biggar

I have a test case:

我有一个测试用例:

class LoginTestCase(unittest.TestCase):
    ...

I'd like to use it in a different test case:

我想在不同的测试用例中使用它:

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

This raises:

这提出:

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

I looked at the unittest code where the exception is being called, and it looks like the tests aren't supposed to be written this way. Is there a standard way to write something you'd like tested so that it can be reused by later tests? Or is there a workaround?

我查看了调用异常的单元测试代码,看起来测试不应该这样编写。是否有一种标准方法可以编写您想要测试的内容,以便以后的测试可以重用?或者有解决方法吗?

I've added an empty runTestmethod to LoginTestas a dubious workaround for now.

我现在添加了一个空runTest方法LoginTest作为一个可疑的解决方法。

采纳答案by Alex Martelli

unittestdoes deep black magic -- if you choose to use it to run your unit-tests (I do, since this way I can use a very powerful battery of test runners &c integrated into the build system at my workplace, but there are definitely worthwhile alternatives), you'd better play by its rules.

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

In this case, I'd simply have EditProfileTestCasederive from LoginTestCase(rather than directly from unittest.TestCase). If there are some parts of LoginTestCasethat you do want to also test in the different environment of EditProfileTestCase, and others that you don't, it's a simple matter to refactor LoginTestCaseinto those two parts (possibly using multiple inheritance) and if some things need to happen slightly differently in the two cases, factor them out into auxiliary "hook methods" (in a "Template Method" design pattern) -- I use all of these approaches often to diminish boilerplate and increase reuse in the copious unit tests I always write (if I have unit-test coverage < 95%, I always feel truly uneasy -- below 90%, I start to feel physically sick;-).

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

回答by Guido U. Draheim

The confusion with "runTest" is mostly based on the fact that this works:

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

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

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

So there is no "runTest" in that class and all of the test-functions are being called. However if you look at the base class "TestCase" (lib/python/unittest/case.py) then you will find that it has an argument "methodName" that defaults to "runTest" but it does NOT have a default implementation of "def runTest"

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

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

The reason that unittest.main works fine is based on the fact that it does not need "runTest" - you can mimic the behaviour by creating a TestCase-subclass instance for all methods that you have in your subclass - just provide the name as the first argument:

unittest.main 工作正常的原因是它不需要“runTest”——您可以通过为子类中的所有方法创建 TestCase-subclass 实例来模拟行为——只需提供名称作为第一个论点:

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)

回答by dmvianna

Here's some 'deep black magic':

这是一些“深邃的黑魔法”:

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

Very handy if you just want to test run your unit tests from a shell (i.e., IPython).

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

回答by Darren McMillan

If you don't mind editing unit test module code directly, the simple fix is to add under case.pyclass TestCasea new method called runTest that does nothing.

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

The file to edit sits under pythoninstall\Lib\unittest\case.py

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

def runTest(self):
    pass

This will stop you ever getting this error.

这将阻止您收到此错误。

回答by Reb.Cabin

@dmvianna's answer got me very close to being able to run unittestin a jupyter (ipython) notebook, but I had to do a bit more. If I wrote just the following:

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

I got

我有


Ran 0 tests in 0.000s

OK


在 0.000 秒内运行 0 个测试

It's not broken, but it doesn't run any tests! If I instantiated the test class

它没有损坏,但它没有运行任何测试!如果我实例化测试类

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

(note the parens at the end of the line; that's the only change) I got

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


ValueError Traceback (most recent call last) in () ----> 1 suite = unittest.TestLoader().loadTestsFromModule (TestStringMethods())

/usr/lib/python2.7/unittest/case.pyc in init(self, methodName) 189 except AttributeError: 190 raise ValueError("no such test method in %s: %s" % --> 191 (self.class, methodName)) 192 self._testMethodDoc = testMethod.doc193 self._cleanups = []

ValueError: no such test method in : runTest


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

/usr/lib/python2.7/unittest/case.pyc在初始化(个体,方法名)189除了AttributeError的:190升ValueError异常( “%s中没有这样的测试方法:%S”。% - > 191(自,methodName)) 192 self._testMethodDoc = testMethod. doc193 self._cleanups = []

ValueError:在:runTest 中没有这样的测试方法

The fix is now reasonably clear: add runTestto the test class:

修复现在相当清楚:添加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 tests in 0.002s

OK


在 0.002 秒内运行 3 个测试

It also works correctly (and runs 3 tests) if my runTestjust passes, as suggested by @Darren.

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

This is a little yucchy, requiring some manual labor on my part, but it's also more explicit, and that's a Python virtue, isn't it?

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

I could not get any of the techniques via calling unittest.mainwith explicit arguments from here or from this related question Unable to run unittest's main function in ipython/jupyter notebookto work inside a jupyter notebook, but I am back on the road with a full tank of gas.

我无法通过unittest.main从这里或从这个相关问题中使用显式参数调用无法获得任何技术无法在 ipython/jupyter 笔记本中运行 unittest 的主要功能以在 jupyter 笔记本中工作,但我带着满满一罐的气体。

回答by saaj

Guido's answer is almost there, however it doesn't explain the thing. I needed to look to unittestcode to grasp the flow.

Guido 的答案几乎就在那里,但它并没有解释这件事。我需要通过unittest代码来掌握流程。

Say you have the following.

假设您有以下情况。

import unittest

class MyTestCase(unittest.TestCase):

  def testA(self):
    pass

  def testB(self):
    pass

When you use unittest.main(), it will try to discover test cases in current module. The important code is unittest.loader.TestLoader.loadTestsFromTestCase.

当您使用 时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

What the latter does, is converting test case class into test suite, that holds the instances of the class per its test method. I.e. my example will be turned into unittest.suite.TestSuite([MyTestCase('testA'), MyTestCase('testB')]). So if you would like to create a test case manually, you need to do the same thing.

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