Merge lp:~lifeless/subunit/docs into lp:~subunit/subunit/trunk
- docs
- Merge into trunk
Proposed by
Robert Collins
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~lifeless/subunit/docs |
Merge into: | lp:~subunit/subunit/trunk |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~lifeless/subunit/docs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jelmer Vernooij | Approve | ||
Review via email: mp+5392@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote : | # |
lp:~lifeless/subunit/docs
updated
- 64. By Robert Collins
-
Missed a bit of dross.
Revision history for this message
Jelmer Vernooij (jelmer) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'README' | |||
2 | --- README 2009-04-07 21:28:28 +0000 | |||
3 | +++ README 2009-04-09 11:44:18 +0000 | |||
4 | @@ -1,5 +1,5 @@ | |||
5 | 1 | 1 | ||
7 | 2 | subunit: extensions to Python unittest to get test results from subprocesses. | 2 | subunit: A streaming protocol for test results |
8 | 3 | Copyright (C) 2005 Robert Collins <robertc@robertcollins.net> | 3 | Copyright (C) 2005 Robert Collins <robertc@robertcollins.net> |
9 | 4 | 4 | ||
10 | 5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
11 | @@ -20,24 +20,27 @@ | |||
12 | 20 | Subunit | 20 | Subunit |
13 | 21 | ------- | 21 | ------- |
14 | 22 | 22 | ||
33 | 23 | Subunit is attempting to extend unittest with a clean and simple api to | 23 | Subunit is a streaming protocol for test results. The protocol is human |
34 | 24 | run arbitrary external test suites and return the results to standard | 24 | readable and easily generated and parsed. By design all the components of |
35 | 25 | Python unittest. | 25 | the protocol conceptually fit into the xUnit TestCase->TestResult interaction. |
36 | 26 | 26 | ||
37 | 27 | Subunit comes in three parts: | 27 | Subunit comes with command line filters to process a subunit stream and |
38 | 28 | * Protocol writers (clients) | 28 | language bindings for python, C, C++ and shell. Bindings are easy to write |
39 | 29 | * Protocol readers (servers) | 29 | for other languages. |
40 | 30 | * Filters | 30 | |
41 | 31 | 31 | A number of useful things can be done easily with subunit: | |
42 | 32 | A reader component acts as a test suite in the language that it is written | 32 | * Test aggregation: Tests run separately can be combined and then |
43 | 33 | for. Currently subunit only provides a Python protocol reader. | 33 | reported/displayed together. For instance, tests from different languages |
44 | 34 | 34 | can be shown as a seamless whole. | |
45 | 35 | Writers output test results in subunit form. Writers are typically | 35 | * Test archiving: A test run may be recorded and replayed later. |
46 | 36 | test suite runners or test suite result objects in specific languages. | 36 | * Test isolation: Tests that may crash or otherwise interact badly with each |
47 | 37 | Currently subunit provides writers for Python, C, C++, and shell. | 37 | other can be run seperately and then aggregated, rather than interfering |
48 | 38 | 38 | with each other. | |
49 | 39 | Filters provide translation filtering capabilities and can be used to modify a | 39 | * Grid testing: subunit can act as the necessary serialisation and |
50 | 40 | stream on-the-fly. Currently subunit provides: | 40 | deserialiation to get test runs on distributed machines to be reported in |
51 | 41 | real time. | ||
52 | 42 | |||
53 | 43 | Subunit supplies the following filters: | ||
54 | 41 | * tap2subunit - convert perl's TestAnythingProtocol to subunit. | 44 | * tap2subunit - convert perl's TestAnythingProtocol to subunit. |
55 | 42 | * subunit2pyunit - convert a subunit stream to pyunit test results. | 45 | * subunit2pyunit - convert a subunit stream to pyunit test results. |
56 | 43 | * subunit-filter - filter out tests from a subunit stream. | 46 | * subunit-filter - filter out tests from a subunit stream. |
57 | @@ -45,96 +48,107 @@ | |||
58 | 45 | * subunit-stats - generate a summary of a subunit stream. | 48 | * subunit-stats - generate a summary of a subunit stream. |
59 | 46 | * subunit-tags - add or remove tags from a stream. | 49 | * subunit-tags - add or remove tags from a stream. |
60 | 47 | 50 | ||
61 | 51 | Integration with other tools | ||
62 | 52 | ---------------------------- | ||
63 | 53 | |||
64 | 54 | Subunit's language bindings act as integration with various test runners like | ||
65 | 55 | 'check', 'cppunit', Python's 'unittest'. Beyond that a small amount of glue | ||
66 | 56 | (typically a few lines) will allow Subunit to be used in more sophisticated | ||
67 | 57 | ways. | ||
68 | 58 | |||
69 | 59 | Python | ||
70 | 60 | ====== | ||
71 | 61 | |||
72 | 62 | As a TestResult, Subunit can translate method calls from a test run into a | ||
73 | 63 | Subunit stream:: | ||
74 | 64 | |||
75 | 65 | # Get a TestSuite or TestCase to run | ||
76 | 66 | suite = make_suite() | ||
77 | 67 | # Create a stream (any object with a 'write' method) | ||
78 | 68 | stream = file('tests.log', 'wb') | ||
79 | 69 | # Create a subunit result object which will output to the stream | ||
80 | 70 | result = subunit.TestProtocolClient(stream) | ||
81 | 71 | # Run the test suite reporting to the subunit result object | ||
82 | 72 | suite.run(result) | ||
83 | 73 | # Close the stream. | ||
84 | 74 | stream.close() | ||
85 | 75 | |||
86 | 76 | As a TestCase, subunit can read from a stream and inform a TestResult | ||
87 | 77 | of the activity from the stream:: | ||
88 | 78 | |||
89 | 79 | # Get a stream (any object with a readline() method), in this case example the | ||
90 | 80 | # stream output by the example before. | ||
91 | 81 | stream = file('tests.log', 'rb') | ||
92 | 82 | # Create a subunit ProtocolTestCase which will read from the stream and emit | ||
93 | 83 | # activity to a result when run() is called. | ||
94 | 84 | suite = subunit.ProtocolTestCase(stream) | ||
95 | 85 | # Create a result object to show the contents of the stream. | ||
96 | 86 | result = unittest._TextTestResult(sys.stdout) | ||
97 | 87 | # 'run' the tests - process the stream and feed its contents to result. | ||
98 | 88 | suite.run(result) | ||
99 | 89 | stream.close() | ||
100 | 90 | |||
101 | 91 | Subunit has support for non-blocking usage too, for use with asyncore or | ||
102 | 92 | Twisted. See the TestProtocolServer class for more details. | ||
103 | 93 | |||
104 | 94 | Building on these foundations, Subunit also offers some convenience tools. | ||
105 | 95 | |||
106 | 96 | The ``IsolatedTestSuite`` class is a decorator that will fork() before running | ||
107 | 97 | the decorated item, and gather the results from the child process via subunit. | ||
108 | 98 | This is useful for handlings tests that mutate global state, or are testing C | ||
109 | 99 | extensions that could crash the VM. | ||
110 | 100 | |||
111 | 101 | Similarly, ``IsolatedTestCase`` is a base class which can be subclassed to get | ||
112 | 102 | tests that will fork() before the test is run. | ||
113 | 103 | |||
114 | 104 | Finally, ``ExecTestCase`` is a convenience wrapper for running an external | ||
115 | 105 | program to get a subunit stream and then report that back to an arbitrary | ||
116 | 106 | result object:: | ||
117 | 107 | |||
118 | 108 | class AggregateTests(subunit.ExecTestCase): | ||
119 | 109 | |||
120 | 110 | def test_script_one(self): | ||
121 | 111 | """./bin/script_one""" | ||
122 | 112 | |||
123 | 113 | def test_script_two(self): | ||
124 | 114 | """./bin/script_two""" | ||
125 | 115 | |||
126 | 116 | # Normally your normal test loading would take of this automatically, | ||
127 | 117 | # It is only spelt out in detail here for clarity. | ||
128 | 118 | suite = unittest.TestSuite([AggregateTests("test_script_one"), | ||
129 | 119 | AggregateTests("test_script_two")]) | ||
130 | 120 | # Create any TestResult class you like. | ||
131 | 121 | result = unittest._TextTestResult(sys.stdout) | ||
132 | 122 | # And run your suite as normal, subunit will exec each external script as | ||
133 | 123 | # needed and report to your result object. | ||
134 | 124 | suite.run(result) | ||
135 | 125 | |||
136 | 126 | C | ||
137 | 127 | = | ||
138 | 128 | |||
139 | 129 | Subunit has C bindings to emit the protocol, and comes with a patch for 'check' | ||
140 | 130 | which has been nominally accepted by the 'check' developers. See 'c/README' for | ||
141 | 131 | more details. | ||
142 | 132 | |||
143 | 133 | C++ | ||
144 | 134 | === | ||
145 | 135 | |||
146 | 136 | C++ uses the C bindings and includes a patch for cppunit. See 'c++/README' for | ||
147 | 137 | details. | ||
148 | 138 | |||
149 | 48 | The subunit code is organised at the top level by directories for language | 139 | The subunit code is organised at the top level by directories for language |
150 | 49 | bindings, and additionally the filters directory for filters. | 140 | bindings, and additionally the filters directory for filters. |
151 | 50 | 141 | ||
239 | 51 | Using subunit in Python | 142 | shell |
240 | 52 | ----------------------- | 143 | ===== |
241 | 53 | 144 | ||
242 | 54 | 1) As a runner for external tests (potentially in other languages) | 145 | Similar to C, the shell bindings consist of simple functions to output protocol |
243 | 55 | 2) As a process boundary for unittest TestCases to prevent them fiddling with | 146 | elements, and a patch for adding subunit output to the 'ShUnit' shell test |
244 | 56 | in-process state (i.e. singletons). | 147 | runner. See 'shell/README' for details. |
245 | 57 | 3) As a wrapper around a TestCase (or Suite) to run a group of tests | 148 | |
246 | 58 | externally. | 149 | |
247 | 59 | 150 | The protocol | |
248 | 60 | 1) As a runner for external tests | 151 | ------------ |
162 | 61 | ================================= | ||
163 | 62 | This is supported on all platforms with Python 2.4. | ||
164 | 63 | For each test script you want to run, declare a ExecTestCase with one | ||
165 | 64 | or more tests whose docstring defines the script to run: | ||
166 | 65 | |||
167 | 66 | import subunit | ||
168 | 67 | import unittest | ||
169 | 68 | class TestCProgram(subunit.ExecTestCase): | ||
170 | 69 | |||
171 | 70 | def test_script_one(self): | ||
172 | 71 | """./bin/script_one""" | ||
173 | 72 | |||
174 | 73 | def test_script_two(self): | ||
175 | 74 | """./bin/script_two""" | ||
176 | 75 | |||
177 | 76 | # Yes, the test prefix on the methods matters. | ||
178 | 77 | # Then run this in whatever normal way you would run Python unittests. | ||
179 | 78 | # If you don't have a specific test runner, you can run it using the | ||
180 | 79 | # default one in unittest.py: | ||
181 | 80 | |||
182 | 81 | if __name__ == '__main__': | ||
183 | 82 | unittest.main() | ||
184 | 83 | |||
185 | 84 | 2) As a process boundary for unittest TestCases | ||
186 | 85 | =============================================== | ||
187 | 86 | This is currently supported only on platforms | ||
188 | 87 | that support os.fork(), which allows us to | ||
189 | 88 | transparently introduce a process boundary | ||
190 | 89 | without affecting manual test parameterisation. | ||
191 | 90 | *** TODO explain in more detail and sketch out | ||
192 | 91 | *** a solution for win32 | ||
193 | 92 | Just import subunit and derive your test cases | ||
194 | 93 | from subunit.IsolatedTestCase: | ||
195 | 94 | |||
196 | 95 | import subunit | ||
197 | 96 | |||
198 | 97 | class TestFoo(subunit.IsolatedTestCase): | ||
199 | 98 | |||
200 | 99 | def test_something_globally(self): | ||
201 | 100 | SomethingGlobal.do() | ||
202 | 101 | self.assertEqual(SomethingGlobal.value(), 3) | ||
203 | 102 | # the run() method of IsolatedTestCase will intercept the | ||
204 | 103 | # test execution, fork() Python to create a new process, | ||
205 | 104 | # then run the test and report the results back to the parent | ||
206 | 105 | # process. | ||
207 | 106 | |||
208 | 107 | # you run this in the normal way you run test cases. | ||
209 | 108 | |||
210 | 109 | 3) As a wrapper around a TestCase to run a group of tests externally. | ||
211 | 110 | ===================================================================== | ||
212 | 111 | |||
213 | 112 | import subunit | ||
214 | 113 | import unittest | ||
215 | 114 | |||
216 | 115 | class TestFoo(unittest.TestCase): | ||
217 | 116 | |||
218 | 117 | def test_foo(self): | ||
219 | 118 | ... | ||
220 | 119 | |||
221 | 120 | |||
222 | 121 | def test_suite(): | ||
223 | 122 | result = subunit.IsolatedTestSuite() | ||
224 | 123 | loader = unittest.TestLoader() | ||
225 | 124 | result.addTest(loader.loadTestsFromName(__name__)) | ||
226 | 125 | return result | ||
227 | 126 | |||
228 | 127 | # you can test the result of test_suite() as follows (or in any normal Python | ||
229 | 128 | # manner. | ||
230 | 129 | runner = unittest.TextTestRunner(verbosity=2) | ||
231 | 130 | runner.run(test_suite()) | ||
232 | 131 | # enjoy. | ||
233 | 132 | |||
234 | 133 | |||
235 | 134 | Some requirements: | ||
236 | 135 | The shape of the external unittest should not need to be known a-priori. | ||
237 | 136 | After the test has run, tests should still exist as discrete objects, so that | ||
238 | 137 | anything taking a reference to them doesn't get 50 copies of the same object. | ||
249 | 138 | 152 | ||
250 | 139 | Sample subunit wire contents | 153 | Sample subunit wire contents |
251 | 140 | ---------------------------- | 154 | ---------------------------- |
252 | @@ -163,7 +177,7 @@ | |||
253 | 163 | 177 | ||
254 | 164 | 178 | ||
255 | 165 | Subunit protocol description | 179 | Subunit protocol description |
257 | 166 | ---------------------------- | 180 | ============================ |
258 | 167 | test|testing|test:|testing: test label | 181 | test|testing|test:|testing: test label |
259 | 168 | success|success:|successful|successful: test label | 182 | success|success:|successful|successful: test label |
260 | 169 | success|success:|successful|successful: test label [ | 183 | success|success:|successful|successful: test label [ |
261 | @@ -211,10 +225,3 @@ | |||
262 | 211 | represented as a successful test in Python. | 225 | represented as a successful test in Python. |
263 | 212 | In future, skip and xfail results will be represented semantically in Python, | 226 | In future, skip and xfail results will be represented semantically in Python, |
264 | 213 | but some discussion is underway on the right way to do this. | 227 | but some discussion is underway on the right way to do this. |
265 | 214 | |||
266 | 215 | |||
267 | 216 | TODO: | ||
268 | 217 | def run: | ||
269 | 218 | do a fork, | ||
270 | 219 | this process runs server | ||
271 | 220 | child runs client and calls self.run() with a SubprocessTestResult | ||
272 | 221 | 228 | ||
273 | === modified file 'c/README' | |||
274 | --- c/README 2007-04-21 07:10:18 +0000 | |||
275 | +++ c/README 2009-04-09 11:39:07 +0000 | |||
276 | @@ -20,12 +20,9 @@ | |||
277 | 20 | This subtree contains an implementation of the subunit child protocol. | 20 | This subtree contains an implementation of the subunit child protocol. |
278 | 21 | Currently I have no plans to write a test runner in C, so I have not written | 21 | Currently I have no plans to write a test runner in C, so I have not written |
279 | 22 | an implementation of the parent protocol. [but will happily accept patches]. | 22 | an implementation of the parent protocol. [but will happily accept patches]. |
281 | 23 | This implementation is build using SCons and tested via 'check'. | 23 | This implementation is built using SCons and tested via 'check'. |
282 | 24 | See the tests/ directory for the test programs. | 24 | See the tests/ directory for the test programs. |
287 | 25 | You can use `make check` or `scons check` to run the tests. I plan to write a | 25 | You can use `make check` or `scons check` to run the tests. |
284 | 26 | 'check' runner which uses these bindings to provide subunit output, at which | ||
285 | 27 | point creating a trivial python test_c.py script which uses the pyunit gui to | ||
286 | 28 | will be added to me todo list. | ||
288 | 29 | 26 | ||
289 | 30 | The C protocol consists of four functions which you can use to output test | 27 | The C protocol consists of four functions which you can use to output test |
290 | 31 | metadata trivially. See lib/subunit_child.[ch] for details. | 28 | metadata trivially. See lib/subunit_child.[ch] for details. |
291 | @@ -34,11 +31,11 @@ | |||
292 | 34 | instance] managing assertions, cleaning up on errors etc. You can look at | 31 | instance] managing assertions, cleaning up on errors etc. You can look at |
293 | 35 | 'check' (http://check.sourceforge.net/) or | 32 | 'check' (http://check.sourceforge.net/) or |
294 | 36 | 'gunit' (https://garage.maemo.org/projects/gunit) for C unit test | 33 | 'gunit' (https://garage.maemo.org/projects/gunit) for C unit test |
298 | 37 | frameworks. I plan to write ui layers for both of these that use the subunit | 34 | frameworks. |
299 | 38 | bindings for reporting. There is a patch for 'check' | 35 | There is a patch for 'check' (check-subunit-*.patch) in this source tree. |
297 | 39 | (check-subunit-0.9.3.patch, and check-subunit-0.9.5.patch) in this source tree. | ||
300 | 40 | Its also available as request ID #1470750 in the sourceforge request tracker | 36 | Its also available as request ID #1470750 in the sourceforge request tracker |
302 | 41 | http://sourceforge.net/tracker/index.php. | 37 | http://sourceforge.net/tracker/index.php. The 'check' developers have indicated |
303 | 38 | they will merge this during the current release cycle. | ||
304 | 42 | 39 | ||
305 | 43 | If you are a test environment maintainer - either homegrown, or 'check' or | 40 | If you are a test environment maintainer - either homegrown, or 'check' or |
306 | 44 | 'gunit' or some other, you will to know how the subunit calls should be used. | 41 | 'gunit' or some other, you will to know how the subunit calls should be used. |
This makes README at least vaguely up to date and interesting to read.