Reputation: 7460
I've written a bunch of tests for my Python application, but they've suddenly appeared to no longer be working properly!
I've created a bunch of tests inside a tests
module:
Inside of tests.__main__.py
, I've included the following code to load my test suite:
import unittest
if __name__ == "__main__":
loader = unittest.TestLoader()
start_dir = "."
suite = loader.discover(start_dir=start_dir, pattern='*_test.py')
runner = unittest.TextTestRunner()
runner.run(suite)
I know I am going to sound like a complete noob, but these tests were working perfectly for me about an hour ago. I would issue them by typing python3 -m tests
from my base directory. However, I'm now receiving a really strange TypeError
:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/Users/yuchen/Desktop/myproj/myapp/tests/__main__.py", line 6, in <module>
suite = loader.discover(start_dir=start_dir, pattern='*_test.py')
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/loader.py", line 341, in discover
tests = list(self._find_tests(start_dir, pattern))
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/loader.py", line 406, in _find_tests
yield from self._find_tests(full_path, pattern, namespace)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/loader.py", line 406, in _find_tests
yield from self._find_tests(full_path, pattern, namespace)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/loader.py", line 398, in _find_tests
full_path, pattern, namespace)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/loader.py", line 452, in _find_test_path
return self.loadTestsFromModule(module, pattern=pattern), False
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/loader.py", line 123, in loadTestsFromModule
tests.append(self.loadTestsFromTestCase(obj))
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/loader.py", line 92, in loadTestsFromTestCase
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/suite.py", line 24, in __init__
self.addTests(tests)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/suite.py", line 57, in addTests
for test in tests:
TypeError: __init__() takes 0 positional arguments but 2 were given
I've followed the stack trace down to what I believe is the appropriate file causing the issue, the suite.py
file of unittest
:
"""TestSuite"""
import sys
from . import case
from . import util
__unittest = True
def _call_if_exists(parent, attr):
func = getattr(parent, attr, lambda: None)
func()
class BaseTestSuite(object):
"""A simple test suite that doesn't provide class or module shared fixtures.
"""
_cleanup = True
def __init__(self, tests=()):
self._tests = []
self._removed_tests = 0
print("Tests", tests) # <--- this was added by me
self.addTests(tests)
However, the __init__()
signature doesn't appear to require 0 positional arguments. Moreover, it's clearly executing, since after I added in print("Tests", tests)
in the code above, I saw the following output before the error was thrown:
Tests: []
Tests: <map object at 0x11033c0b8>
Tests: <map object at 0x11033c0b8>
Tests: <map object at 0x11033c0b8>
Tests: [<unittest.suite.TestSuite tests=[... a list of my tests]]
Tests: <map object at 0x110483978>
Tests: <map object at 0x110483978>
Traceback (most recent call last):
I'm pretty at a loss for what is going on. The error printed in the stack trace doesn't appear to correspond at all with what I'm seeing in the source code.
Edit (Resolution):
The accepted answer was spot on. I had written another test class, and decided to simply add in a stub for the __init__
method:
class MyUnfinishedTest(BaseTest):
def __init__():
pass
Then I had forgotten about it and worked on other stuff, and ran the tests. That's when I started seeing my error. After removing this class from my test module, the tests ran smoothly.
Upvotes: 2
Views: 494
Reputation: 23004
One of the reasons that the traceback seems a little confusing is that the line:
for test in tests
is actually hitting a generator, which is discovering and loading the tests on the fly.
So I'm guessing that this:
TypeError: __init__() takes 0 positional arguments but 2 were given
actually means that the discovery process has found a test class it cannot load, possibly because that class has its own __init__
method with a different number of arguments to what discover expects.
I would double-check your test classes for __init__
methods, and possibly also change this line:
start_dir = "."
to:
start_dir = os.path.dirname(__file__)
That would mean that the discovery process would start looking from the tests
folder down, which is safer than "." (current working directory) because the current working directory might change depending upon where you start the tests from (and may end up picking up tests that you weren't expecting).
Upvotes: 1