]> git.wincent.com - WOTest.git/blob - NOTES.txt
Code clean-up for garbage collection
[WOTest.git] / NOTES.txt
1 ================================================================================
2 What is WOTest?
3 ================================================================================
4
5
6
7 ================================================================================
8 WOTest quickstart (code snippets and questions)
9 ================================================================================
10
11 Quick code snippets:
12
13 // loading the framework
14 WO_TEST_LOAD_FRAMEWORK;
15
16 // testing to see if the framework is loaded
17 if (!WO_TEST_FRAMEWORK_IS_LOADED)
18 {
19     // ...
20 }
21
22 // performing some tests
23 WO_TEST_EQUAL(object1, object2);
24 WO_TEST_NOT_EQUAL(variable1, variable2);
25
26 // shorthand form for tests
27 WO_TEST_EQ(object1, object2);
28 WO_TEST_NE(variable1, variable2);
29 WO_TEST(assertion); // short form of WO_TEST_TRUE
30
31 // writing a test method
32 - (void)testNetworkHandler
33 {
34     WO_TEST_TRUE([[ABNetworkManager sharedManager] isConnected]);
35 }
36
37 Quick questions and answers:
38
39 Q: How do I install the WOTest.framework?
40 A: You don't have to install the WOTest.framework.
41
42 Q: How do I link against the WOTest.framework?
43 A: You don't have to link against the framework.
44
45 Q: Where do I put my tests? In a bundle? A framework? Inside my classes?
46 A: You can put the tests anywhere you like.
47
48 ================================================================================
49 Requirements
50 ================================================================================
51
52 In order to build WOTest the Wincent Buildtools are required. They can be obtained from:
53
54 http://wincent.com/a/products/buildtools/
55
56 ================================================================================
57 Why YAUTF (Yet Another Unit Testing Framework)?
58 ================================================================================
59
60 There are already a number of unit testing frameworks available for use with Objective-C (see "Other unit testing frameworks" for a possibly incomplete list). They each have distinct benefits to offer; some are very mature and in widespread use, others are especially "light weight", and others have a raft of functionality.
61
62 But there are a lot of approaches (design philosophies) to unit testing and choosing between them is a very personal question. I chose to write WOTest because: firstly, none of the existing solutions matched my personal tastes; and secondly, because I see writing my own code as a valuable learning experience.
63
64 Below is the set characteristics I wanted for WOTest which I couldn't find in an existing packages. In general I found that the available tools met some of these criteria but not all of them, and they generally forced me work in a way which I didn't really like. Given that the proposed design for WOTest was so light-weight, it seemed like a better idea to spend a few days writing the code rather than learn/tame any of the existing packages.
65
66 1. Extremely light-weight. My unit testing needs are fairly modest. I don't do "Test-Driven Development" ("TDD"; where you write the tests before you write the program); rather I write the tests as I go along as a means of quality control (and of course, along the way there are "moments" of TDD). I don't need an exhaustive feature set.
67
68 2. "Airtight" compartmentalization between product code ("the product") and the code that runs the tests ("the tests"). I don't want the test code to be interspersed throughout product's code. I want to be able to look at all the tests for a product in one location. There are three schools of thought on this:
69 (a) That the tests should be right next to the code being tested, in the same file. This is the way I used to work, a strong argument for this method is that it is much easier to keep the tests updated as you modify the code, and much easier in general to switch back and forth between the tests and the code being tested. The main weakness of this method is that there is no easy way to see all the tests at once, and it is also very difficult to remove the tests or deactivate them without resorting to the use of ugly preprocessor macros;
70 (b) That the tests should be in separate files that are closely related to the code being tested, for example, in subclasses that test their superclasses, or in categories that test their associated classes. Because the tests are in separate files they are easier to deactivate or excluded from code shipped to users, but you still can't see all the tests at once and the "parallel hierarchy problem" (see below) becomes more of an issue;
71 (c) That the tests should be cleanly separated from the product code, together in one place (all in one file, if you desire). This is the method used by WOTest. The main benefits of this method is that you can easily see all the tests at once, the tests can be easily removed or deactivated, and the "parallel hierarchy problem" is avoided. The down side, in common with method (b), is that you must keep two editors open (one for the tests, one for the tested code) if you want to look at both at the same time. In reality this is not as bad as it sounds because firstly, method (b) is actually much more complicated because it requires you to look through multiple files in order to navigate through your test suite, and secondly, method (a) loses some of its simplicity when you're dealing with large and complicated classes (even when the tests are in the same file as the tested code, if there is a lot of code then the scrolling and navigation ceases to be trivial).
72
73 3. Xcode integration. It should be easy to automatically run the test suite from within Xcode, and not just by performing a "Run" (Command-R) but as a part of the actual build process (Command-B). You should be able to click on failed test results and be taken to the corresponding line in the source code.
74
75 4. Separation of test target and non-test target. It should be possible to have a target in Xcode that doesn't run any tests, and a separate target that does run the tests.
76
77 5. No parallel hierarchies (either class hierarchies or category hierarchies). It shouldn't be necessary to maintain two hierarchies of code (one for the product and one for the tests) which could get out of synchronization (see the following two points).
78
79 6. No subclasses. It shouldn't be necessary to write subclasses (containing "the tests") in order to test classes (containing "the product"). I don't like this because it requires the incidental work of setting up interfaces and implementations. If the subclasses are in separate files then the work is greater because you have to worry about header files as well, and you've fall straight into the trap of maintaining parallel class hierarchies.
80
81 7. No categories. It shouldn't be necessary to write categories (containing "the tests") in order to test classes (containing "the product"). Once again, I don't like the incidental work involved.
82
83 8. Ability to test applications, frameworks (in isolation), or applications that link against frameworks.
84
85 9. Ability to run unit tests from within the debugger.
86
87 9. The code that ships should be tested, not the code that doesn't ship. I don't want to only test the "Development" build of the product and then ship an (untested!) "Deployment" build. Nor do I want to test a selection of classes from the product in isolation (for example, taking the source files for those selected classes and compiling them into my test suite). I want to test the exact code which will ship to customers.
88
89 10. Customers and beta-testers should be able to run the tests (if you want them to, that is). It's useful that third parties can run the tests for the purposes of support or squishing bugs. It is possible that the tests may pass "in house", but fail on other hardware or other configurations, and information gathered on those configurations is of obvious value.
90
91 11. The testing mechanism should be transparent (invisible) to those who have no interest in using it. The option to run the tests should be exactly that: optional; and the tests and the option to run them itself should not even be visible to those customers who don't wish to run the tests. In effect this means that the test materials should be easily embeddable within the shipped product's bundle.
92
93 12. Shipping the tests with the code should not affect the performance or memory use of the product. Because the framework is so light-weight (only a few kilobytes on disk), it can be shipped with the product without significantly contributing to the download size. The compartmentalization of the tests, combined with the fact that they are entirely optional, means that users not running the tests suffer no performance penalty (not only do the tests not run, the tests and the test framework are not even loaded into memory).
94
95 13. Setting up test suites and adding tests should be extremely easy.
96
97 14. Test framework should be embeddable or installable.
98
99 15. Should be able to use the test framework without linking to it (ie. there should be no performance or memory penalty for those who do not wish to perform testing).
100
101 Needless to say, WOTest is not the "Swiss Army Knife" of unit testing tools. It was not designed to be flexible and adapt to a huge range of different possible workflows. There are already enough tools out there for that. It is designed to exactly fit one workflow, mine, and I'm releasing it because there may be other people out there who like to work in the same way as I do.
102
103 Despite this, it turns out that the design of WOTest allows you to do quite a lot more with it than implement the specific workflow for which I wrote it. For example, WOTest can do the following:
104
105 - work as a separate project from the product to be tested; work as a separate target within the project of the product to be tested; work embedded in the actual target of the product to be tested;
106
107 - perform the tests during a build phase within Xcode; perform the tests when run from within Xcode; perform the tests when run from the command-line;
108
109 - find tests in separate bundles or frameworks; find tests in separate files within a project (subclasses, separate classes, categories, or methods added to an existing class); find tests embedded in the class files of a project (subclasses, separate classes, categories, or methods added to an existing class);
110
111 This documentation focuses on my own workflow, but makes brief references to how WOTest can be used in the different ways referred to above (see the section "Other workflow permutations" below).
112
113 ================================================================================
114 Background
115 ================================================================================
116
117 When I first heard about Unit Testing it sounded like a great idea. I wasn't such a big fan of the so called "Extreme Programming" movement as a whole; the advocates' eyes would glaze over as they pounded and thumped their desks with their fists while extolling the merits of their guiding principles (a collection of acronyms and Wiki-ready phrases jammed together into long words), and clutched their Extreme Programming tomes to their chests as though they were sacred religious texts. Lots of solid, good ideas, but taken a little too seriously and fanatically for my liking (and I am a Mac user, by definition somewhat "fanatical"). And all too frequently they claimed that those who disagreed with them did so only because they didn't understand (or weren't capable of understanding) their point of view (in other words, that they hadn't yet attained "enlightenment"). You can't blame them for feeling enthusiastic about something, but their dogmatic, polemical style smacks of close-mindedness and an unwillingness to recognise that other people may have alternative and valid points of view.
118
119 But yes, the idea of unit testing did appeal to me. I looked at the existing unit test solutions and didn't really like any of them. They all seemed highly complicated (at least to my beginner's eyes) and required me to installed third-party frameworks and command-line tools and goodness knows what else. It all seemed like overkill when all I really wanted to do was a series of very basic assertions, like the following pseudo-code:
120
121     if (result of function != expected result)
122         report error;
123
124 There's a lot more to it than that, but this is what essentially lies at the heart of unit testing. So instead of grappling with any of those tools, I came up with a set of macros that enabled me to do unit testing. Here is a basic example:
125
126     #ifdef DEBUG
127
128     /*! Test for a positive result (> 0) */
129     #define WO_TEST_POSITIVE(expr)                                          \
130     do {                                                                    \
131         if ((expr) <= 0)                                                    \
132             ELOG(@"Unit test failed (expected POSITIVE; obtained <= 0)");   \
133     } while (0)
134
135     #else /* DEBUG not defined*/
136
137     #define WO_TEST_POSITIVE(expr)
138
139     #endif
140
141 The ELOG macro was defined elsewhere, and logged the class, method, line number and so forth where the error was produced. Note that when the DEBUG flag is not defined (as is the case with "Deployment" builds), the tests produce no code. This means that the tests don't wind up in production code shipped to customers (which was in keeping with my goal at the time), but the down side is that the code that is tested is the "Development" build and not the "Deployment" build. It's conceivable (although it never happened to me) that tests could pass in the Development build yet the same function could fail in the "real world" deployment build.
142
143 In the end I had quite an elaborate set of unit testing macros, all in all totalling a few hundred lines, that met my needs for a long time. These tests weren't bad; they were very easy to add to a project and they could be easily run in the debugger. On the down side, you had to run the product (specifically the "Development" build) in order to perform the tests, which means you couldn't click on the test results in Xcode and be taken to the corresponding line and file.
144
145 Then while reading Apple's cocoa-dev mailing list I heard about UnitKit. I took a look at it. In my view, UnitKit is the most light-weight and easy-to-learn unit testing solution out there. UnitKit's integration with Xcode was great because the tests could be tacked on to the "Build" phase and the test results could easily be clicked on and you'd be automatically taken to the appropriately line and file.
146
147 For reasons I've already stated above, I decided to build my own testing framework. I'm a perfectionist, and although UnitKit is a great little piece of software, it didn't work exactly how my personal tastes would dictate. Also, UnitKit development stopped once Apple started shipping OCUnit with its Xcode Tools. I wrote WOTest from scratch and didn't use any code from UnitKit. The truth is that I barely even looked at that code. But I still want to recognise the efforts of James Duncan Davidson (the principal author of UnitKit) because his work basically inspired me to write WOTest, and provided me with the key idea for how to achieve integration with Xcode.
148
149 The internals of WOTest are a little more simple, it has quite a few more test types, but it sticks to the basic core idea of UnitKit that makes it so well intergrated with Xcode: using preprocessor macros so that the inbuilt __FILE__ and __LINE__ macros can be used to generate output that Xcode will interpret and allow users to click on results and be taken to the right file and line. Like UnitKit, WOTest tries to keep the minimum amount of test logic in the macros and keep most of the logic in a set up underlying Objective-C methods, because writing, testing and debugging methods is more straightforward than writing complex macros.
150
151
152
153
154 ================================================================================
155 WOTest can test itself
156 ================================================================================
157
158 Before I could use it to test itself, I had to complete a significant proportion of the code. "Test-Driven Development" was not an option, because until I had written the testing mechanism I didn't even know how I could write the tests. Now that WOTest is basically complete, it can be used to test itself. The key piece that needed to be written before I could start using WOTest to test itself was the WOTestRunner command-line executable.
159
160 The tests appear in the file, "WOTestSelfTests.m". The file is a fairly comprehensive example of the kinds of tests that are possible with WOTest. Because the objective is to test the tests, all of the test methods include two approaches to the testing: one batch of tests that are expected to pass (in other words, if a test passes when it is expected to pass, then this is a pass); and a second batch of tests that are expected to fail (in other words, if a test fails a test when it is expected to fail, then this also is a pass). In this respect, this shows a highly atypical application of the tests; generally you would write code with the intention that all tests should pass, but in order to test that the tests work you must show that the both pass when you expect them to pass and fail when you expect them to fail.
161
162 However, the presence of all those failure warnings in the build log can make the test results hard to read. For this reason, WOTest implements a special variable (expectFailures) that should be used only during WOTest self-testing. When the flag is set, in addition to the standard "Failed" and "Passed" status messages, there are an additional two messages: "Failed (expected failure)" and "Passed (unexpected pass)". Normally in your own unit tests you wouldn't need to set the expectFailures variable; rather you would write tests such that an expected failure results in pass. This is much safer, because there's no risk of you setting the expectFailures variable to YES and later forgetting to set it back to NO.
163
164 ================================================================================
165 Linking to WOTest.framework
166 ================================================================================
167
168 You don't have to link to WOTest.framework, and there are a couple of reasons why you wouldn't want to. WOTest has been carefully designed so that you don't have to link if you don't want to.
169
170 When you link to WOTest.framework you increase the size of your executable file on disk by a small amount (this is true of any framework). Furthermore, your executable will use more memory than it would have had you not linked to WOTest.framework. This is true even if you link but never make any calls to methods in the framework. This is bad because it means that if you decide to ship your product with the unit tests included, then all users will see a slight increase in disk and memory usage, even those who don't have any interest in running the tests. One way to work around this problem is to have two versions of the product, one for internal testing (that links against WOTest.framework) and one for external deployment, but that breaks one of the design goals for WOTest of being able to test the exact product (bit for bit) that gets shipped to customers.
171
172 Luckily, thanks to the dynamic nature of the Objective-C runtime, it's possible to elegantly get around this problem. It's possible to have your product dynamically load the WOTest.framework (in other words, no linking) if and only if the user explicitly instructs it to do so; at all other times the framework doesn't get loaded. Because there's no linking, it means the executable size doesn't swell, and those users who don't want to run the tests don't see any increase in memory usage. You're then left with a simple choice: distribute the WOTest.framework along with your product if you want users to be able to test it; or just distribute the product on its own if you don't want to offer testing capability. In either case the product is exactly the same and performs exactly the same.
173
174 To illustrate how this works, consider the following example. Imagine a tool that does not link against Apple's AppKit framework, but nevertheless wants to create an NSView object:
175
176 #import <AppKit/AppKit.h>
177
178 - (void)callAppKitMethod
179 {
180     NSView *aView = [[NSView alloc] initWithFrame:NSZeroRect];
181 }
182
183 By including the AppKit header file you ensure that the compiler doesn't give you any warnings, but if you try to build such code the linker will give you an error that "NSView" is an undefined symbol. Of course, even if you could produce an executable and run it, it wouldn't work because the executable isn't linked to the AppKit.framework. One way to force the framework to load is to set environment variables and then run the product from the command-line. For example, in the bash shell:
184
185 export DYLD_FRAMEWORK_PATH=/System/Library/Frameworks
186 export DYLD_INSERT_LIBRARIES=/System/Library/Frameworks/AppKit.framework/AppKit
187 /path/to/executable
188
189 On running, the executable has access to all of the AppKit.framework's classes, even though it didn't link to them. But this still doesn't solve the problem that the linker will complain about undefined symbols. One way around this is to pass "-undefined define_a_way" to the linker when building your executable (see the ld (1) man page for more options).
190
191 A far more elegant way to solve this problem is to take advantage of the dynamic nature of the Objective-C runtime. The product doesn't need to link against the framework, there is no need to set linker options, export environment variables, or run the product from the command-line. The following code illustrates:
192
193 #import <AppKit/AppKit.h>
194
195 - (void)callAppKitMethod
196 {
197     NSBundle *theBundle =
198     [NSBundle bundleWithPath:@"/System/Library/Frameworks/AppKit.framework"];
199     Class   viewClass   = [theBundle classNamed:@"NSView"];
200     NSView  *aView      = [[viewClass alloc] initWithFrame:NSZeroRect];
201 }
202
203 No compiler warnings, no linker errors, everything just works. WOTest uses this technique to allow you to load code "on the fly" without having to link to it. All it has to do is look for bundles, load them, and then run the test methods on them.
204
205 ================================================================================
206 How to test frameworks
207 ================================================================================
208
209 Let's take an example framework, "Example.framework". As a developer, you want to be able to build the framework and test it. You then want to ship the framework to customers. You don't want to have to engage in multiple builds (one for testing, one for shipping). The WOTest.framework is used to perform tests and report the results. The WOTestRunner commandline executable is the tool that loads the testing framework and the framework-to-be-tested into memory and then runs the tests.
210
211 You have multiple options for where you put the tests:
212
213 1. Embed them in Example.framework itself. This requires you to link against the WOTest.framework, otherwise you'll get warnings for undefined symbols. It will also swell the memory footprint of your framework even if the user never runs the tests.
214
215 In this case you'll just run WOTestRunner and pass "Example.framework" as a command-line parameter.
216
217 2. Stick them in separate framework or loadable bundle; call it "Tests.framework" or "Tests.bundle". Link against "WOTest.framework" and the framework you want to test so that the linker doesn't give you warnings about undefined symbols.
218
219 In this case you'll run WOTestRunner and pass both "Example.framework" and "Tests.framework" or "Tests.bundle" as command-line parameters.
220
221 WOTestRunner loads the code from the frameworks into memory and runs all eligible test, reporting the results.
222
223 Framework search order:
224
225 ~/Library/Frameworks/
226 ~/Developer/Frameworks/
227 /Library/Frameworks/
228 /Developer/Frameworks/
229 /Network/Library/Frameworks/
230 /Network/Developer/Frameworks/
231 /System/Library/Frameworks/
232
233 0. These instructions assume a shared build products location. For example:
234
235 ~/build/WOTest.framework
236 ~/build/FrameworkBeingTested.framework
237 ~/build/FrameworkBeingTested.framework/Versions/A/Resources/FrameworkTests.bundle
238 ~/build/OtherFrameworkLinkedToByFrameworkBeingTested.framework
239
240 Need to make sure these instructions work when embedded inside an application.
241 And need to find a way to easily test everything at once for end-users... eg. user runs tests on application and application fires off tests on applications too
242
243 1. In your framework project create a new group called "FrameworkTests" (or some other distinguishing label).
244
245 2. From the "Project" menu select "New Target...".
246
247 3. Choose "Loadable Bundle" from the "Cocoa" group.
248
249 4. Name the target "FrameworkTests" (or some other distinguishing label).
250
251 5. In the Target properties window that appears click the plus button to add the framework as a direct dependency of the test bundle. You can add WOTest.framework as a dependency as well if you want to make sure it gets built when required as part of the build process (rather than using a pre-built copy).
252
253 5b. Add "-noprebind" to the "OTHER_LDFLAGS_ppc" build setting for the target if necessary to silence warnings.
254
255 6. Xcode will create a plist file with a name like "FrameworkTests-Info.plist" which you can drag into the "FrameworkTests" group.
256
257 7. Set the "CFBundleIdentifier" in the info plist file to something appropriate, like "com.wincent.SynergyAdvanceFrameworkTests".
258
259 8. Select the "FrameworkTests" group and from the "File" menu choose "New File..."
260
261 9. Choose "Objective-C class" from the "Cocoa" group and choose an appropriate filename such as "FrameworkTests.m".
262
263 10. In the header ("FrameworkTests.h") mark your test class with the "<WOTest>" protocol marker and add this import statement.
264
265 #import "WOTest/WOTest.h"
266
267 11. In the implementation file write your tests. The methods should start with "- (void)test".
268
269 12. Link the FrameworkTests bundle against Foundation.framework (or Cocoa.framework) or whatever other frameworks your test framework links to and the framework that you wish to test. It is not necessary to link to the WOTest.framework itself, but you can if you want to use the WOMock class.
270
271 12b. Add WOTest to the project as a dependency, to ensure it gets built if required.
272
273 12c. You may need to add "$(TARGET_BUILD_DIR)" to your "Header Search Paths" for the test target.
274
275 13. Add a "Run Script" phase to the target that handles the packaging:
276
277 # copy the test bundle into its final location
278 ${CP} -fRv "${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}" "${TARGET_BUILD_DIR}/SynergyAdvance.framework/Versions/A/Resources/"
279
280 # make the frameworks folder relative to WOTestRunner (@executable_path/../Frameworks/)
281 /bin/mkdir -pv "${TARGET_BUILD_DIR}/SynergyAdvance.framework/Versions/A/Frameworks"
282
283 # provide a symlink so that the bundle can find the framework
284 cd "${TARGET_BUILD_DIR}/SynergyAdvance.framework/Versions/A/Frameworks"
285 /bin/ln -fsv ../../../../WOTest.framework WOTest.framework
286 =====
287 export DYLD_FRAMEWORK_PATH="${TARGET_BUILD_DIR}"
288
289 "${TARGET_BUILD_DIR}/WOTest.framework/Versions/A/Resources/WOTestRunner" \
290 --test-bundle="${TARGET_BUILD_DIR}/SynergyAdvance.framework/Versions/A/Resources/${FULL_PRODUCT_NAME}"
291 =====
292
293
294 include information on how to set this up as a custom executable too (works: see WODebug for an example)
295 useful for running WOTestRunner under GDB
296
297
298 ================================================================================
299 How to test applications
300 ================================================================================
301
302 Testing frameworks is relatively easy because they are self-contained pieces of functionality. You can create a test bundle that links against the framework and then use the test runner to load the test bundle and run the tests, thus testing the framework.
303
304 Testing an application is slightly different. You can't use the test runner to run an application. You can put your tests in a bundle and use the BUNDLE_LOADER build setting to inform that linker that it should look for any missing symbols in the executable (but not with dead code stripping turned on, unless you use the WO_TEST_NO_DEAD_STRIP_CLASS macro). You can then employ some dynamic loading trickery to load the bundle from the application and run the tests.
305
306 Injecting a test bundle into a running application. Example taken from REnamer.app:
307
308 export WOTestInjectBundle="/Users/wincent/trabajo/build/Release/REnamer.app/Contents/Resources/ApplicationTests.bundle"
309 export DYLD_INSERT_LIBRARIES="/Users/wincent/trabajo/build/Release/REnamer.app/Contents/Frameworks/WOTest.framework/WOTest"
310 export DYLD_PRINT_LIBRARIES=1
311 /Users/wincent/trabajo/build/Release/REnamer.app/Contents/MacOS/REnamer
312
313 ================================================================================
314 Shipping testable production applications
315 ================================================================================
316
317 ================================================================================
318 Shipping non-testable production applications
319 ================================================================================
320
321 ================================================================================
322 Shipping testable frameworks
323 ================================================================================
324
325
326 ================================================================================
327 Shipping non-testable frameworks
328 ================================================================================
329
330
331 ================================================================================
332 Other workflow permutations
333 ================================================================================
334
335 The suggested workflow that's documented above is based on adding a new target to the product that is to be tested and writing all of the tests inside of that target. WOTest was designed to enable this workflow. Nevertheless, the dynamic nature of the Objective-C runtime means that you can actually use WOTest in quite a few different ways and everything keeps on working as you would expect. Some alternative workflows are briefly discussed below.
336
337 - Putting the tests inside an existing target
338
339 - Putting the tests inside a separate project
340
341 - Putting the tests inside subclasses (same files)
342
343 - Putting the tests inside subclasses (separate files)
344
345 - Putting the tests inside categories (same files)
346
347 - Putting the tests inside categories (separate files)
348
349
350 ================================================================================
351 FAQ (Frequently Asked Questions)
352 ================================================================================
353
354 * How do I avoid the warning, "comparison between signed and unsigned, to avoid this warning use an explicit cast"?
355
356 Either cast an unsigned value to a signed value:
357
358     number -> (int)number
359
360 Or a signed value to an unsigned one:
361
362     number -> (unsigned)number
363
364 A common cause of this warning is comparing an unsigned return value to a literal constant number:
365
366     WO_TEST_EQ([object length], 10);
367
368 This is because the length method returns an unsigned value, but the compiler sees the number 10 as a signed value. One solution is:
369
370     WO_TEST_EQ([object length], 10U);
371
372 ================================================================================
373 Donations
374 ================================================================================
375
376 WOTest is free software released under the GPL license. If it is useful to you, please consider making a donation:
377
378 https://www.paypal.com/xclick/business=win@wincent.com&item_name=WOTest+donation&no_note=1&currency_code=EUR&lc=en
379
380
381 ================================================================================
382 Other unit testing frameworks that work with Objective-C
383 ================================================================================
384
385 ObjCUnit:   http://oops.se/objcunit/                    (last updated 2002)
386
387 OCUnit:     http://www.sente.ch/software/ocunit/        (included with Xcode Tools)
388
389 TestKit:    http://testkit.sourceforge.net/             (last updated 2004)
390             http://sourceforge.net/projects/testkit
391
392 UnitKit:    http://unitkit.org/                         (discontinued)
393
394
395 ================================================================================
396 How it works
397 ================================================================================
398
399 Project A
400 --> Target: normal target
401
402 --> Target: unit test target
403 ----> Dependency: normal target
404
405 To perform the unit testing, build the unit test target:
406 1. This first builds the project's normal target.
407 2.A. Then it proceeds to build the unit test target.
408 2.B. The unit test target contains a shell script phase that runs the WOTestRunner tool, passing the project's normal target bundle as a parameter.
409 2.C. WOTestRunner loads the bundle and searches for all classes that correspond to the WOTest protocol.
410 2.D. All conforming classes are searched for methods that begin with the word "test".
411 2.E. Matching methods are invoked. Class methods are invoked first. Then, for each instance method, a new object is created using alloc/init, the test method is invoked, and the object is released. If a non-standard init method is required then the appropriate method should be invoked from within a class test method.
412
413 An example class:
414
415 class: WOFoo
416 method: +testEncryption
417
418 1. WOTestRunner loads WOFoo's bundle
419 2. WOTestRunner finds WOFoo class
420 3. WOTestRunner tests to see whether WOFoo conforms to the WOTest protocol
421 4. WOTestRunner finds methods starting with "test"
422 5. WOTestRunner runs the +testEncryption method
423 6. The +testEncryption method contains a macro with the __FILE__ and __LINE__ passed as parameters
424 7. The +testEncryption method calls a test method in the WOTest.framework
425 8. If the test succeeds, a message is logged to stdout
426 9. If the test fails, a message is logged to stderr in the appropriate format
427
428
429 stderr reporting format: warnings:
430
431 /full/path:line_number: warning: message
432
433 errors:
434
435 /full/path:line_number: error: message
436
437
438
439
440 ================================================================================
441 Notes about mock objects
442 ================================================================================
443
444 OCMock requires you to have a class which responds to all the selectors you want to mock. WOTest allows you to mock anything without writing anything. You do need to have the class that's being mocked available at runtime, but it can be totally empty.
445
446
447 ================================================================================
448 Namespace issues
449 ================================================================================
450
451 WOTest adds a number of methods to existing Foundation classes via categories. All added methods are prefixed with the "WOTest_" suffix to avoid namespace clashes with the software being tested. Yes it's ugly, and yes such names are not suitable for use in a Key/Value Coding context, but the methods are intended for internal use within WOTest only and so the tradeoff is deemed worthwhile.
452
453
454 ================================================================================
455 Author contact and website
456 ================================================================================
457
458 Author:             Wincent Colaiuta <win@wincent.com>
459 Product website:    http://test.wincent.com/
460
461 ================================================================================
462 Credits and thanks
463 ================================================================================
464
465 Thanks James Duncan Davidson (UnitKit) for providing the inspiration to make a lean and elegant unit testing framework.
466
467 http://unitkit.org/
468
469 Thanks to Mulle Kybernetik (OCMock) for the idea of using the trampoline paradigm to elegantly implement mock objects.
470
471 http://www.mulle-kybernetik.com/software/OCMock/
472
473 ================================================================================
474 License and warranty
475 ================================================================================
476
477 WOTest is licensed under the GNU GPL (General Public License). It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file LICENSE.txt for more details.