]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/ |
2 | / Copyright (c) 2003 Boost.Test contributors | |
3 | / | |
4 | / Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | /] | |
7 | ||
8 | [section:fixtures Fixtures] | |
9 | In general terms a test fixture or test context is the collection of one or more of the following items, required | |
10 | to perform the test: | |
11 | ||
12 | * preconditions | |
13 | * particular states of tested units | |
14 | * necessary cleanup procedures | |
15 | ||
16 | Though these tasks are encountered in many if not all test cases, what makes a test fixture different is | |
17 | repetition. Where a normal test case implementation does all preparatory and cleanup work itself, a test fixture | |
18 | allows it to be implemented in a separate reusable unit. | |
19 | ||
20 | With introduction of e[*X]treme [*P]rogramming (XP), the testing style, that require test setup/cleanup repetition, | |
21 | has become even more popular. Single XP adopted test modules may contain hundreds of single assertion test cases, | |
22 | many requiring very similar test setup/cleanup. This is the problem that the test fixture is designed to solve. | |
23 | ||
24 | In practice a test fixture usually is a combination of `setup` and `teardown` functions, associated with test case. | |
25 | The former serves the purposes of test setup. The later is dedicated to the cleanup tasks. Ideally we'd like for a | |
26 | test module author to be able to define variables used in fixtures on the stack and, at the same time, to refer to | |
27 | them directly in a test case. | |
28 | ||
29 | It's important to understand that C++ provides a way to implement a straightforward test fixture solution | |
30 | that almost satisfies our requirements without any extra support from the test framework. Here is how simple test | |
31 | module with such a fixture may look like: | |
32 | ||
33 | `` | |
34 | struct MyFixture { | |
35 | MyFixture() { i = new int; *i = 0 } | |
36 | ~MyFixture() { delete i; } | |
37 | ||
38 | int* i; | |
39 | }; | |
40 | ||
41 | __BOOST_AUTO_TEST_CASE__( test_case1 ) | |
42 | { | |
43 | MyFixture f; | |
44 | // do something involving f.i | |
45 | } | |
46 | ||
47 | __BOOST_AUTO_TEST_CASE__( test_case2 ) | |
48 | { | |
49 | MyFixture f; | |
50 | // do something involving f.i | |
51 | } | |
52 | `` | |
53 | ||
54 | ||
55 | This is a generic solution that can be used to implement any kind of shared setup or cleanup procedure. Still | |
56 | there are several more or less minor practical issues with this pure C++ based fixtures solution: | |
57 | ||
58 | * We need to add a fixture declaration statement into each test case manually. | |
59 | * Objects defined in fixture are references with `<fixture-instance-name>` prefix. | |
60 | * There is no place to execute a ['global] fixture, which performs ['global] setup/cleanup | |
61 | procedures before and after testing. | |
62 | ||
63 | The __UTF__ lets you define a fixture according to [link boost_test.tests_organization.fixtures.models several generic interfaces], | |
64 | and thus helps you with following tasks: | |
65 | ||
66 | * define shared setup/teardown procedures for a single or group of test cases | |
67 | * define setup/teardown procedures which are performed once per test suite | |
68 | * define global setup/teardown procedures which are performed once per test module | |
69 | ||
70 | [/ ###################################################################################### ] | |
71 | [section:models Fixture models] | |
72 | ||
73 | Several fixture interfaces are supported by the __UTF__. The choice of the interface depends | |
74 | mainly on the usage of the fixture. | |
75 | ||
76 | [h3 Fixture class model] | |
77 | The __UTF__ defines the generic fixture class model as follows: | |
78 | ||
79 | `` | |
80 | struct <fixture-name>{ | |
81 | <fixture-name>(); // setup function | |
82 | ~<fixture-name>(); // teardown function | |
83 | }; | |
84 | `` | |
85 | ||
86 | In other words a fixture is expected to be implemented as a class where the class constructor serves as a `setup` | |
87 | method and class destructor serves as `teardown` method. The __UTF__ opted to avoid explicit names in fixture | |
88 | interface for `setup` and `teardown` methods, since it is considered most natural in C++ for tasks similar to RAII and | |
89 | coincides with the pure C++ solution discussed above. | |
90 | ||
91 | This model is expected from fixtures used with __BOOST_FIXTURE_TEST_CASE__ and __BOOST_FIXTURE_TEST_SUITE__. | |
92 | ||
93 | [caution The above interface prevents you from reporting errors in the `teardown` procedure using an exception. It does make | |
94 | sense though: if somehow more than one fixture is assigned to a test unit (e.g. using __decorator_fixture__ decorator), | |
95 | you want all `teardown` procedures to run, even if some may experience problems. | |
96 | ] | |
97 | ||
98 | ||
99 | [h3 Flexible models] | |
100 | In addition to __BOOST_FIXTURE_TEST_CASE__ and __BOOST_FIXTURE_TEST_SUITE__ the __UTF__ allows to associate fixture with | |
101 | test unit using the decorator __decorator_fixture__. This decorator supports additional models for declaring | |
102 | the `setup` and `teardown`: | |
103 | ||
104 | * a fixture defined according to the fixture class model above | |
105 | * a fixture defined according to the extended fixture class model, which allows for the fixture constructor to | |
106 | takes one argument. For example: | |
107 | ||
108 | struct Fx | |
109 | { | |
110 | std::string s; | |
111 | Fx(std::string s = "") : s(s) | |
112 | { BOOST_TEST_MESSAGE("set up " << s); } | |
113 | ~Fx() { BOOST_TEST_MESSAGE("tear down " << s); } | |
114 | }; | |
115 | ||
116 | * a fixture defined as a pair of free functions for the `setup` and `teardown` (latter optional) | |
117 | ||
118 | void setup() { BOOST_TEST_MESSAGE("set up"); } | |
119 | void teardown() { BOOST_TEST_MESSAGE("tear down"); } | |
120 | ||
121 | For complete example of test module which uses these models please check decorator __decorator_fixture__. | |
122 | ||
123 | [endsect] [/section generic fixture] | |
124 | ||
125 | ||
126 | ||
127 | [/ ###################################################################################### ] | |
128 | [section:case Test case fixture] | |
129 | A /test case fixture/ is a fixture consumed by a test case: the fixture `setup` is called before the test case executes, | |
130 | and the fixture `teardown` is called after the test case finished its execution, independently from its execution state. | |
131 | ||
132 | The __UTF__ provides several ways of defining fixtures for test-cases, each of which having their properties: | |
133 | ||
134 | * the declaration of a fixture for a single test case, letting the test case access the members of the fixture, | |
135 | * the declaration of one or more fixture(s) for a single test case, without accessing the members and with a flexible interface, | |
136 | * the declaration of a fixture for a group of test-cases defined by a subtree, with access to the members of the fixture. | |
137 | ||
138 | ||
139 | [h3 Single test case fixture] | |
140 | The following two methods are available for declaring a fixture attached to one particular test case: | |
141 | ||
142 | * the use of the macro __BOOST_FIXTURE_TEST_CASE__ in place of __BOOST_AUTO_TEST_CASE__, which let access to the members of the fixture | |
143 | * the use of the decorator __decorator_fixture__, which does not let access to the members but enables | |
144 | the definition of several fixtures for one test case. | |
145 | ||
146 | [/ ------------------------------------------------------------------------ ] | |
147 | [#test_case_fixture_macro][h4 Fixture with `BOOST_FIXTURE_TEST_CASE`] | |
148 | ||
149 | `BOOST_FIXTURE_TEST_CASE` serves as a test case declaration with a fixture, and is meant be used in place of | |
150 | the test case declaration with __BOOST_AUTO_TEST_CASE__: | |
151 | ||
152 | `` | |
153 | BOOST_FIXTURE_TEST_CASE(test_case_name, fixture_name); | |
154 | `` | |
155 | ||
156 | The only difference from the macro __BOOST_AUTO_TEST_CASE__ is the presence of an extra argument `fixture_name`. | |
157 | The public and protected members of the fixture are directly accessible from the test case body. Only | |
158 | one fixture can be attached to a test-case [footnote it is still possible to define a class inheriting from several | |
159 | fixtures, that will act as a proxy fixture.]. | |
160 | ||
161 | [note You can't access private members of fixture, but then why would you make anything private?] | |
162 | ||
163 | [bt_example example18..Per test case fixture..run-fail] | |
164 | ||
165 | In this example only `test_case1` and `test_case2` have fixture `F` assigned. | |
166 | You still need to refer to the fixture name in every test case. [link test_case_fixture_subtree This] section | |
167 | explains how a same fixture can be declared for a subtree under a test suite. | |
168 | ||
169 | [/ ------------------------------------------------------------------------ ] | |
170 | [#test_case_fixture_decorator][h4 Fixture with `fixture` decorator] | |
171 | By using the decorator __decorator_fixture__, it is possible to: | |
172 | ||
173 | * attach several fixtures to a unique test case | |
174 | * use a flexible fixture interface (see [link boost_test.tests_organization.fixtures.models here]) | |
175 | ||
176 | [note Using the decorator approach, it is not possible to access the members of the fixture (in case the fixture is implemented | |
177 | as a class)] | |
178 | ||
179 | ||
180 | ||
181 | [/ ###################################################################################### ] | |
182 | [#test_case_fixture_subtree][h3 Fixture for a complete subtree] | |
183 | ||
184 | If all test cases in a test sub tree require the same fixture (you can group test cases in a test suite based on a | |
185 | fixture required) you can make another step toward an automation of a test fixture assignment. To assign the | |
186 | same shared fixture for all test cases in a test suite, use the macro __BOOST_FIXTURE_TEST_SUITE__ in place of the | |
187 | macro __BOOST_AUTO_TEST_SUITE__ for automated test suite creation and registration. | |
188 | ||
189 | `` | |
190 | BOOST_FIXTURE_TEST_SUITE(suite_name, fixture_name); | |
191 | `` | |
192 | ||
193 | Once again the only difference from the macro __BOOST_AUTO_TEST_SUITE__ usage is the presence of | |
194 | an extra argument - the fixture name. And now, you not only have direct access to the public and protected members | |
195 | of the fixture, but also do not need to refer to the fixture name in test case definition. All test cases assigned | |
196 | the same fixture automatically. | |
197 | ||
198 | [tip If necessary you can reset the fixture for a particular test case using the macro | |
199 | __BOOST_FIXTURE_TEST_CASE__. Similarly you can reset the fixture for a particular sub | |
200 | test suite using __BOOST_FIXTURE_TEST_SUITE__. | |
201 | ] | |
202 | ||
203 | [note The fixture assignment is ['deep]. In other words unless reset by another | |
204 | __BOOST_FIXTURE_TEST_SUITE__ or __BOOST_FIXTURE_TEST_CASE__ definition the | |
205 | same fixture is assigned to all test cases of a test suite, including ones that belong to the sub test suites. | |
206 | ] | |
207 | ||
208 | [bt_example fixture_02..Test suite level fixture..run] | |
209 | ||
210 | [caution The fixture constructor and destructor is called for each test cases (the state of the | |
211 | fixture is not shared among the test cases).] | |
212 | ||
213 | ||
214 | ||
215 | [endsect] [/ per test case] | |
216 | ||
217 | [/ ###################################################################################### ] | |
218 | [section:per_test_suite_fixture Test suite entry/exit fixture] | |
219 | ||
220 | It is possible to define a test suite entry/exit fixture, so that the `setup` function is called only once upon entering | |
221 | the test suite, prior to running any of its test cases; and similarly the `teardown` function is also called only once | |
222 | upon the test suite exit, after all the enclosed test cases have been run. This is facilitated by the | |
223 | /decorator/ __decorator_fixture__. | |
224 | ||
225 | [bt_example fixture_03..Test suite entry/exit fixture..run] | |
226 | ||
227 | In case of this fixture type, however, it is not possible to access any members of the fixture object. | |
228 | ||
229 | [caution This is not equivalent to using the method described [link test_case_fixture_subtree here].] | |
230 | ||
231 | [endsect] [/ per_test_suite_fixture] | |
232 | ||
233 | [/ ###################################################################################### ] | |
234 | [section:global Global fixture] | |
235 | ||
236 | Any global initialization that needs to be performed every time testing begins or a global cleanup that is to be | |
237 | performed once testing is finished is called a global fixture. The __UTF__ global fixture design is based on the | |
238 | [link boost_test.tests_organization.fixtures.models generic test class fixture model]. The global | |
239 | fixture design allows any number of global fixtures to be defined in any test file that constitutes a test module. | |
240 | Though some initialization can be implemented in the test module initialization function, there are several | |
241 | reasons to prefer the global fixture approach: | |
242 | ||
243 | * There is no place for cleanup/`teardown` operations in the initialization function. | |
244 | * Unlike the initialization function, the global fixture `setup` method invocation is guarded by the execution | |
245 | monitor. That means that all uncaught errors that occur during initialization are properly reported. | |
246 | * Any number of different global fixtures can be defined, which allows you to split initialization code by | |
247 | category. | |
248 | * The fixture allows you to place matching `setup`/`teardown` code in close vicinity in your test module code. | |
249 | * If the whole test tree is constructed automatically the initialization function is empty and auto-generated by | |
250 | the __UTF__. To introduce the initialization function can be more work than the use of a global fixture facility, | |
251 | while global fixture is more to the point. | |
252 | * Since all fixtures follow the same generic model you can easily switch from local per test case fixtures to | |
253 | the global one. | |
254 | * If you are using the interactive test runner (non-supplied yet) global test fixtures are applied to every run, | |
255 | while an initialization function is executed only once during a test module startup (just make sure that | |
256 | it's what you really want). | |
257 | ||
258 | To define a global test module fixture you need to implement a class that matched generic fixture model and | |
259 | passed it as an argument to the macro __BOOST_GLOBAL_FIXTURE__. | |
260 | ||
261 | `` | |
262 | BOOST_GLOBAL_FIXTURE(fixture_name); | |
263 | `` | |
264 | ||
265 | The statement, that performs global fixture definition, has to reside at a test file scope. | |
266 | ||
267 | [bt_example example20..Global fixture..run] | |
268 | ||
269 | [endsect] [/section Global fixtures] | |
270 | ||
271 | [endsect] [/ section fixtures] | |
272 | ||
273 | [/EOF] |