flesh out readme
[third_party/subunit] / README
1     
2   subunit: extensions to python unittest to get test results from subprocesses.
3   Copyright (C) 2005  Robert Collins <robertc@robertcollins.net>
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19
20
21 Subunit is attempting to extend unittest with a clean and simple api to
22 run arbitrary external test suites and return the results to standard 
23 python unittest.
24
25 Using subunit:
26
27 1) As a runner for external tests (potentially in other languages)
28 2) As a process boundary for unittest TestCases to prevent them fiddling with 
29    in-process state (i.e. singletons).
30 3) As a wrapper around a TestCase (or Suite) to run a group of tests 
31    externally.
32
33 1) As a runner for external tests
34 =================================
35 This is supported on all platforms with python 2.4.
36 For each test script you want to run, declare a ExecTestCase with one
37 or more tests whose docstring defines the script to run:
38
39 import subunit
40 import unittest
41 class TestCProgram(subunit.ExecTestCase):
42
43     def test_script_one(self):
44         """./bin/script_one"""
45
46     def test_script_two(self):
47        """./bin/script_two"""
48
49 # Yes, the test prefix on the methods matters.
50 # Then run this in whatever normal way you would run python unittests.
51 # If you don't have a specific test runner, you can run it using the
52 # default one in unittest.py:
53  
54 if __name__ == '__main__':
55      unittest.main()
56
57 2) As a process boundary for unittest TestCases
58 ===============================================
59 This is currently supported only on platforms
60 that support os.fork(), which allows us to 
61 transparently introduce a process boundary
62 without affecting manual test parameterisation.
63 *** TODO explain in more detail and sketch out
64 *** a solution for win32
65 Just import subunit and derive your test cases 
66 from subunit.IsolatedTestCase:
67
68 import subunit
69
70 class TestFoo(subunit.IsolatedTestCase):
71
72     def test_something_globally(self):
73         SomethingGlobal.do()
74         self.assertEqual(SomethingGlobal.value(), 3)
75         # the run() method of IsolatedTestCase will intercept the
76         # test execution, fork() python to create a new process, 
77         # then run the test and report the results back to the parent
78         # process.
79
80 # you run this in the normal way you run test cases.
81
82 3) As a wrapper around a TestCase to run a group of tests externally.
83 =====================================================================
84 This hasn't been implemented yet, but it will look something like:
85
86 import subunit
87 import unittest
88
89 class TestFoo(unittest.TestCase):
90
91     def test_foo(self):
92         ...
93
94
95 def test_suite():
96     result = subunit.IsolatedTestSuite()
97     loader = unittest.TestLoader()
98     result.addTestCase(loader.loadTestsFromName(__name__))
99     return result
100
101 # you can test the result of test_suite() as follows (or in any normal python
102 # manner.
103 runner = unittest.TextTestRunner(verbosity=2)
104 runner.run(test_suite())
105 # enjoy.
106
107     
108 Some requirements:
109   The shape of the external unittest should not need to be known a-priori.
110   After the test has run, tests should still exist as discrete objects, so that
111   anything taking a reference to them doesn't get 50 copies of the same object.
112
113
114 TEST: test foo works
115 SUCCESS: test foo works.
116 TEST: tar a file.
117 FAILURE: tar a file. [
118 ..
119  ]..  space is eaten.
120 foo.c:34 WARNING foo is not defined.
121 ]
122 a writeln to stdout
123
124 ===========
125 .F
126 a writeln to stdout
127
128 ========================
129 FAILURE: tar a file.
130 -------------------
131 ..
132 ]..  space is eatern.
133 foo.c:34 WARNING foo is not defined.
134 ========================
135
136 control protocol: 
137 test|testing|test:|testing: test label
138 success|success:|successful|successful: test label
139 failure test label
140 failure: test label
141 failure test label [
142 ...
143 ]
144 failure: test label [
145 ...
146 ]
147 error: test label
148 error: test label [
149 ]
150 unexpected output on stdout -> stdout.
151 exit w/0 or last test -> error
152
153 TODO:
154 def run:
155     do a fork,
156       this process runs server
157       child runs client and calls self.run() with a SubprocessTestResult