Tested with Python 2.7.12 on Linux.
I am trying to write a simple function that decorates a test_*
method in unittest.TestCase
. I know that methods that do not begin with test_
are not considered actual tests and are not invoked directly when the test is run. I then wondered what you happen if you took a test_
method and applied a naive decorator to it that made no attempt to preserve the name. I was expecting my test to be ignored and to have to modify my decorator to make sure that the function has a name beginning with test_
. I was very, very surprised when the test ran anyway.
Here's the directory layout of the example
.
|-- add.py
|-- print_args.py
|-- test_add.py
`-- test_add_decorated.py
0 directories, 4 files
add.py
is the library we are testing. It adds two things.
def add(x, y):
return x + y
print_args.py
is a library containing a decorator that prints the args and kwargs of a function as a side effect. It is written as naively as possible and makes no attempt to preserve the name of the function.
def print_args(wrapped):
def wrapper(*args, **kwargs):
print [args, kwargs]
return apply(wrapped, args, kwargs)
return wrapper
Here is test_add.py
which imports add.py
and tests that 4 + 5 = 9
. The __repr__
method of TestAdd
is not directly relevant to this example, but will be in the next one.
import unittest
import add
class TestAdd(unittest.TestCase):
def __repr__(self):
return "I am a unittest.TestCase! Fear me!"
def test_add(self):
self.assertEqual(add.add(4, 5), 9)
if __name__ == "__main__":
unittest.main()
When we run test_add.py
, we can see that one test ran and it passed.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Now we apply the decorator to the test_add
method in test_add_decorated.py
.
import unittest
import print_args
import add
class TestAdd(unittest.TestCase):
def __repr__(self):
return "I am a unittest.TestCase! Fear me!"
@print_args.print_args
def test_add(self):
self.assertEqual(add.add(4, 5), 9)
if __name__ == "__main__":
unittest.main()
Before I ran this, I was expecting to see no errors, but an indication that zero tests had run, since the test_add
method's name should now be wrapper
.
That is not what happened. The print_args
decorator worked fine, we can see the args and kwargs in an array and an indication that one test ran successfully.
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
[(I am a unittest.TestCase! Fear me!,), {}]
So, my question is ... how did the unittest
library figure out that it was supposed to run my decorated method?
The wrapper function's __name__
might be wrapper
, but it's still TestAdd.test_add
. As in, if you look at the TestAdd
class's __dict__
, you'll find the wrapper function bound to key 'test_add'
, and if you wanted to call the method, you would use the name test_add
, not wrapper
.
When unittest
uses method names to determine whether a method is a test, it doesn't look at the __name__
. It looks at what attribute name the method is associated with, and the decorator doesn't affect that.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments