Python unittesting method call issue

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sat Sep 27 22:19:11 EDT 2014


Milson Munakami wrote:

> I am trying to set the precondition for the test first prior to test other
> test cases. But as you can see in my code the precondition print command
> is not fired! Can you explain the cause and solution how to fire the code
> with in that method i.e. SetPreConditionFirewall() with setup variable
> self.<variablename> in this fucntion. Here is my code:

Unfortunately, your code has many issues. See comments below, interleaved
between the lines of code:


[snip imports]
> class testFirewallS1( unittest.TestCase ):
>     def setUp(self):
>         self.controllerIp="127.0.0.1"
>     def tearDown(self):
>         if self.failed:
>             return

I cannot see that self.failed is defined anywhere, so your tearDown method
will fail every single time a test runs.

>         duration = time.time() - self.startTime_

I cannot see that self.startTime_ is defined anywhere either.

>         self.cleanup(True)
>         if self.reportStatus_:

Nor self.reportStatus_.

>             self.log.info("=== Test %s completed normally (%d sec)",
>                           self.name_, duration)

And the same for self.log, self.name_.

>     def cleanup(self, success):
>         sys.excepthook = sys.__excepthook__

I don't know why you are doing this. Your code never changes the excepthook,
so why are you restoring it? It seems unnecessary.

>         try:
>             return
>         except NameError:

A bare return cannot possibly fail. It certainly won't fail with NameError,
so your "except NameError" clause is dead code and will never run.

>             self.log.error("Exception hit during cleanup,
>                            bypassing:\n%s\n\n" % traceback.format_exc())
>             pass

But if it did run, the "pass" here is pointless and unnecessary.

>         else:
>                 fail("Expected a NameError")

This code will never run, since you've already returned out of the method.
It is dead code.

If you want to raise an exception, the right way is with the "raise"
keyword:

    raise NameError

not to invent some fake name which you hope will fail.


>     def SetPreConditionFirewall(self):
>         command = "http://%s:8080/wm/firewall/module/enable/json" %
self.controllerIp
>         urllib.urlopen(command).read() 
>         print self.controllerIp
>         print "Test Pre-condition setting here"


Here you have a test method, which the unittest framework will automatically
detect, if you allow it. But later, you explicitly provide a method name
for the test suite to run, so there is a conflict: will the unittest
framework call your explicitly named method, or your test* methods, or
both? I'm afraid I don't know that answer to that, but I expect that the
solution is to use one, or the other, not both.

>     #Precondition Test
>     def testPreConditionFirewall(self):
>         print "Test pass"
> 
> def suite():
>         suite = unittest.TestSuite()
>         suite.addTest(unittest.makeSuite(testFirewallS1))
>         return suite

I'm not sure why you are manually instantiating TestSuite here, instead of
allowing unittest to do so on your behalf. But since you never actually
call suite(), it doesn't matter, it doesn't get used.


> if __name__ == '__main__':
>         suiteFew = unittest.TestSuite()
>         testFirewallS1("SetPreConditionFirewall")

Here you create a testFirewallS1 instance, but it is immediately garbage
collected since you don't do anything with it.


>         suiteFew.addTest(testFirewallS1("testPreConditionFirewall"))

Again, I'm not sure why you are bothering to manually create test suites.
Can you explain what you are trying to do?


>         #Testing the Test Cases Begins Here
>         unittest.TextTestRunner(verbosity=2).run(suiteFew)
> 
> How can I do access that method on __main__ and how can that method can
> access the setup variable.

What method on __main__? I don't understand your question.

In my opinion, I don't see anything that requires you to manually
instantiate the test suites. I think you should let the unittest framework
handle all the grunt work. Start by defining one or more test suites, by
inheriting from TestCase, then let unittest auto-detect and auto-run them.
The simplest way is to just name your tests "testFoo" (for any value of
Foo).


class TestFirewallS1(unittest.TestCase):
    # Write your setUp and tearDown methods, if you need them.
    # Make sure you initialise all the attributes you need. The best
    # place for that is in the setUp method.

    def setUp(self):
        self.variable = "World"

    # Now write your tests. Prefix them with the word "test".
    def test_this(self):
        # Write a self-contained test. It can call any helper methods
        # you like, access any instance attributes you have.
        result = self.helper() + self.variable
        self.assertEqual(result, "HelloWorld!")

    # Methods not starting with "test" are not special.
    def helper(self, arg=None):
        return "Hello"

    # And another test.
    def test_that(self):
        x = 100*3  # Do some calculation.
        self.assertNotEqual(x, -1)

class TestFirewallS2(unittest.TestCase):
    def test_stuff(self):
        self.assertTrue(isinstance(self, unittest.TestCase))


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


The framework will:

- discover the test suites (classes that inherit from TestCase);
- do test discovery (methods beginning with the word "test");
- instantiate each test suite;
- run the tests;
- run the setUp method (if any) before each test;
- run the tearDown method (if any) after each test;
- collect the results and display them.

unittest.main() will check the commandline to see if you passed "--verbose"
as an argument:

    python path/to/your/test_file.py --verbose


or you can force it in your code:

    unittest.main(verbosity=2)



-- 
Steven




More information about the Python-list mailing list