ValueError: no such test method in : runTest

后端 未结 6 1008
时光取名叫无心
时光取名叫无心 2020-12-03 03:10

I have a test case:

class LoginTestCase(unittest.TestCase):
    ...

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

class Edi         


        
相关标签:
6条回答
  • 2020-12-03 03:44

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

    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"

    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:

    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)
    
    0 讨论(0)
  • 2020-12-03 03:44

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

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

    def runTest(self):
        pass
    

    This will stop you ever getting this error.

    0 讨论(0)
  • 2020-12-03 03:50

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

    0 讨论(0)
  • 2020-12-03 03:57

    unittest does 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.

    In this case, I'd simply have EditProfileTestCase derive from LoginTestCase (rather than directly from unittest.TestCase). If there are some parts of LoginTestCase that 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 LoginTestCase into 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;-).

    0 讨论(0)
  • 2020-12-03 04:00

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

    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

    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.doc 193 self._cleanups = []

    ValueError: no such test method in : runTest

    The fix is now reasonably clear: add runTest to the test class:

    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

    It also works correctly (and runs 3 tests) if my runTest just passes, as suggested by @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?

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

    0 讨论(0)
  • 2020-12-03 04:03

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

    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.

    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.

    0 讨论(0)
提交回复
热议问题