I find it a bit irritating getting so much details for a simple failed unit test. Is it possible to suppress everything but the actual defined assert message?
Creating test database for alias 'default'...
.F
======================================================================
FAIL: test_get_sales_item_for_company (my_app.tests.SalesItemModelTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/kave/projects/my/my_app/tests.py", line 61, in test_get_sales_item_for_company
self.assertEqual(sales_items.count(), 1, 'Expected one sales item for this company, but got %s' % sales_items.count())
AssertionError: Expected one sales item for this company, but got 2
----------------------------------------------------------------------
Ran 2 tests in 0.313s
FAILED (failures=1)
Destroying test database for alias 'default'...
I find this bit unnecessary. I need to know the test name (method) that failed and the assert message. No need for traceback really..
Traceback (most recent call last):
File "/home/kave/projects/my/my_app/tests.py", line 61, in test_get_sales_item_for_company
self.assertEqual(sales_items.count(), 1, 'Expected one sales item for this company, but got %s' % sales_items.count())
Monkey patching to the rescue. You can get rid of the traceback for failures without touching your Django installation by subclassing Django's TestCase as follows:
import types
from django.utils.unittest.result import failfast
from django.test import TestCase
@failfast
def addFailureSansTraceback(self, test, err):
err_sans_tb = (err[0], err[1], None)
self.failures.append((test, self._exc_info_to_string(err_sans_tb, test)))
self._mirrorOutput = True
class NoTraceTestCase(TestCase):
def run(self, result=None):
result.addFailure = types.MethodType(addFailureSansTraceback, result)
super(NoTraceTestCase, self).run(result)
Now just make your test cases subclasses of NoTraceTestCase
instead of TestCase
and you are good to go. No more tracebacks for failures. (Note exceptions will still print tracebacks. You could monkey-patch those away similarly if you wanted to.)
Here's how it works (with thanks to Jason Pratt for the quick lesson on monkey patching):
Django's test runner calls TestCase's run
method for each test run. The result
parameter is an instance of the django.utils.unittest.result.TestResult
class, which handles showing test results to the user. Whenever a test fails, run
makes the following call: result.addFailure(self, sys.exc_info())
. That's where the traceback comes from -- as the third item in the tuple returned by sys.exc_info()
.
Now, simply overriding run
with a copy of the original code and tweaking it as needed would work. But the run
method is a good 75 lines long, and all that needs to be changed is that one line, and in any case why miss out the chance for some fun with monkey-patching?
The result.addFailure
assignment changes the addFailure
method in the result
object that is passed to NoTraceTestCase's run
method to the newly defined addFailureSansTraceback
function -- which is first transformed into a result
-object compatible method with types.MethodType
.
The super
call invokes Django's existing TestCase run
. Now, when the existing code runs, the call to addFailure
will actually call the new version, i.e. addFailureSansTraceback
.
addFailureSansTraceback
does what the original version of addFailure
does -- copying over two lines of code -- except adds a line that replaces the traceback with None
(the assignment to err_sans_tb
which is used instead of err
in the next line). That's it.
Note the original addFailure
has a failfast
decorator, so that is imported and used. To be honest, I haven't looked at what it does!
Disclaimer: I haven't studied Django's test code thoroughly. This is just a quick patch to get it to work in the common case. Use at your own risk!
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