SubUnit is a streaming protocol for test results. It allows communication between unit tests and a test harness. Originally developed for unit testing in 2005 by Robert Collins. Subunit comes with command line filters to process a SubUnit stream and language bindings for Python, C, C++ and Shell. Bindings are easy to write for other languages.
A number of useful things can be done easily with SubUnit:
- Test aggregation: Tests run separately can be combined and then reported/displayed together.
- Test archiving: A test run may be recorded and replayed later.
- Test isolation: Tests that may crash or otherwise interact badly with each other can be run separately and then aggregated.
- Grid testing: SubUnit can act as the necessary serialisation and deserialiation to get test runs on distributed machines to be reported in real time.
There are two major revisions of the protocol. Version 1 was trivially human readable but had significant defects as far as highly parallel testing was concerned - it had no room for doing discovery and execution in parallel, required substantial buffering when multiplexing and was fragile - a corrupt byte could cause an entire stream to be misparsed. Version 1.1 added encapsulation of binary streams which mitigated some of the issues but the core remained.
Version 2 shares many of the good characteristics of Version 1 - it can be embedded into a regular text stream (e.g. from a build system) and it still models xUnit style test execution. It also fixes many of the issues with Version 1 - Version 2 can be multiplexed without excessive buffering (in time or space), it has a well defined recovery mechanism for dealing with corrupted streams (e.g. where two processes write to the same stream concurrently, or where the stream generator suffers a bug).
Here's an example of SubUnit general format:
time: 2016-03-24 21:05:38.652075Z test: mytest.SampleTestCase.runTest failure: mytest.SampleTestCase.runTest [ Traceback (most recent call last): File "/media/windows/dev/java/qaworkspace/pythonnosetests/src/mytest.py", line 11, in runTest self.assertEqual(len(s), 4, 'Wrong length') AssertionError: Wrong length ] time: 2011-05-2322:49:38.858163Z