Django: How to hide Traceback in unit tests for readability?

I find this a bit annoying, getting so many details for a simple failed unit test. Is it possible to suppress everything except the actual specific 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 name of the test (method) that failed, and the assert message. No trace needed 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()) 
+4
source share
1 answer

Monkey patches for help. You can get rid of tracing for crashes without touching the Django installation by subclassing Django 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 subclass the NoTraceTestCase test cases instead of TestCase , and you will do a good job. No more traces of failure. (Note that exceptions will still print traces. You could behead them too if you wanted to.)

Here's how it works (thanks to Jason Pratt for a quick monkey fix tutorial ):

  • Django test drive calls the TestCase run method for each test run. The result parameter is an instance of the django.utils.unittest.result.TestResult class, which processes the test results to the user. Whenever a test fails, run makes the following call: result.addFailure(self, sys.exc_info()) . Where the trace comes from is like the third element in the tuple returned by sys.exc_info() .

  • Now just overriding run with a copy of the source code and tweaking it as needed will work. But the run method is 75 lines long, and all you need to change is one line, and anyway, why not miss the chance to enjoy decapitation?

  • The purpose of result.addFailure changes the addFailure method in the result object, which is passed to the NoTraceTestCase run method for the new addFailureSansTraceback function, which is first converted to a result object compatible with types.MethodType .

  • Calling super calls Django an existing TestCase run . Now that the existing code is running, calling addFailure will actually invoke the new version, i.e. addFailureSansTraceback .

  • addFailureSansTraceback does what the original version of addFailure β€” copy over two lines of code β€” except add a line that replaces the trace with None (assigning err_sans_tb , which is instead of err in the next line). What is it.

  • Note that the original addFailure has a addFailure decorator, so it is imported and used. Honestly, I did not watch what he was doing!

Disclaimer: I have not studied the Django test code. This is just a quick patch to make it work in general. Use at your own risk!

+1
source

All Articles