I have some basic setup/teardown code that I want to reuse in a whole bunch of unit tests. So I got the bright idea of creating some derived classes to avoid repeating code in every test class.
In so doing, I received two strange errors. One, I cannot solve. Here is the unsolvable one:
AttributeError: 'TestDesktopRootController' object has no attribute '_testMethodName'
Here is my base class:
import unittest import twill import cherrypy from cherrypy._cpwsgi import CPWSGIApp class BaseControllerTest(unittest.TestCase): def __init__(self): self.controller = None def setUp(self): app = cherrypy.Application(self.controller) wsgi = CPWSGIApp(app) twill.add_wsgi_intercept('localhost', 8080, lambda : wsgi) def tearDown(self): twill.remove_wsgi_intercept('localhost', 8080)
And here is my derived class:
import twill from base_controller_test import BaseControllerTest class TestMyController(BaseControllerTest): def __init__(self, args): self.controller = MyController() BaseControllerTest.__init__(self) def test_root(self): script = "find 'Contacts'" twill.execute_string(script, initial_url='http://localhost:8080/')
The other strange error is:
TypeError: __init__() takes exactly 1 argument (2 given)
The "solution" to that was to add the word "args" to my __init__
function in the derived class. Is there any way to avoid that?
Remember, I have two errors in this one.
There are two ways you can use assertRaises: using keyword arguments. Just pass the exception, the callable function and the parameters of the callable function as keyword arguments that will elicit the exception. Make a function call that should raise the exception with a context.
assertRaises(exception, callable, *args, **kwds) Test that an exception (first argument) is raised when a function is called with any positional or keyword arguments. The test passes if the expected exception is raised, is an error if another exception is raised, or fails if no exception is raised.
The try block lets you test a block of code for errors. The except block lets you handle the error. The else block lets you execute code when there is no error. The finally block lets you execute code, regardless of the result of the try- and except blocks.
b) self.id returns the name of method The test object is represented by the string returned. The string returned consists of the full name of the test method, It's module name, it's class name.
It's because you're overriding __init__()
incorrectly. Almost certainly, you don't want to override __init__()
at all; you should do everything in setUp()
. I've been using unittest
for >10 years and I don't think I've ever overridden __init__()
.
However, if you really do need to override __init__()
, remember that you don't control where your constructor is called -- the framework calls it for you. So you have to provide a signature that it can call. From the source code (unittest/case.py
), that signature is:
def __init__(self, methodName='runTest'):
The safe way to do this is to accept any arguments and just pass 'em up to the base class. Here is a working implementation:
class BaseTest(unittest.TestCase): def __init__(self, *args, **kwargs): unittest.TestCase.__init__(self, *args, **kwargs) def setUp(self): print "Base.setUp()" def tearDown(self): print "Base.tearDown()" class TestSomething(BaseTest): def __init__(self, *args, **kwargs): BaseTest.__init__(self, *args, **kwargs) self.controller = object() def test_silly(self): self.assertTrue(1+1 == 2)
In BaseController
's __init__
you need to call unittest.TestCase
's __init__
just like you did in TestMyController
.
The call to construct a TestCase from the framework may be passing an argument. The best way to handle this for deriving classes is:
class my_subclass(parentclass): def __init__(self, *args, **kw): parentclass.__init__(self, *args, **kw) ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With