I've been playing with Kiwi and I'm trying some BDD (Behavior Driven Development) for a new static library component I wanted to build. I began with a new Xcode project using the Static Library template, but ran into issues with the difference between "logic tests" and "application tests". In short, all my non-UIKit code worked great, until I started to test my UIKit related functions.
The code crashed and makes it frustrating to write unit tests. If you've never experienced it before, it'll make your unit test experience unproductive. To solve the issue you'll need to create a new target (empty iOS application) and include unit tests. Xcode will automagically setup the unit tests to be "Application Tests" instead of "logic tests."
#0 0x00a40881 in __HALT () #1 0x0097a971 in _CFRuntimeCreateInstance () #2 0x01337cc1 in GSFontCreateWithName () #3 0x05c32281 in UINewFont () #4 0x05c323ec in +[UIFont systemFontOfSize:traits:] () #5 0x05c32438 in +[UIFont systemFontOfSize:] () #6 0x05be24ee in +[UILabel defaultFont] () #7 0x05be32e5 in -[UILabel _commonInit] () #8 0x05be3424 in -[UILabel initWithFrame:] () #9 0x05e7cc67 in -[UIAlertView(Private) _createTitleLabelIfNeeded] () #10 0x05e8b4b9 in -[UIAlertView setTitle:] () #11 0x05e8bb37 in -[UIAlertView initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles:] () #12 0x02605831 in __block_global_23 at /Users/paulsolt/dev/Photo-Slide-Show/PSMessages/PSMessagesTests/PSMessagesTest.m:165 #13 0x0261b584 in __25-[KWExample visitItNode:]_block_invoke_0 at /Users/paulsolt/dev/Photo-Slide-Show/Frameworks/Kiwi/Kiwi/KWExample.m:220 #14 0x0261a11e in __42-[KWContextNode performExample:withBlock:]_block_invoke_0 at /Users/paulsolt/dev/Photo-Slide-Show/Frameworks/Kiwi/Kiwi/KWContextNode.m:116 #15 0x0261a11e in __42-[KWContextNode performExample:withBlock:]_block_invoke_0 at /Users/paulsolt/dev/Photo-Slide-Show/Frameworks/Kiwi/Kiwi/KWContextNode.m:116 #16 0x0261a11e in __42-[KWContextNode performExample:withBlock:]_block_invoke_0 at /Users/paulsolt/dev/Photo-Slide-Show/Frameworks/Kiwi/Kiwi/KWContextNode.m:116 #17 0x0261a03e in -[KWContextNode performExample:withBlock:] at /Users/paulsolt/dev/Photo-Slide-Show/Frameworks/Kiwi/Kiwi/KWContextNode.m:132 #18 0x0261a05d in -[KWContextNode performExample:withBlock:] at /Users/paulsolt/dev/Photo-Slide-Show/Frameworks/Kiwi/Kiwi/KWContextNode.m:135 #19 0x0261a05d in -[KWContextNode performExample:withBlock:] at /Users/paulsolt/dev/Photo-Slide-Show/Frameworks/Kiwi/Kiwi/KWContextNode.m:135 #20 0x0261b539 in -[KWExample visitItNode:] at /Users/paulsolt/dev/Photo-Slide-Show/Frameworks/Kiwi/Kiwi/KWExample.m:216 #21 0x0261a553 in -[KWItNode acceptExampleNodeVisitor:] at /Users/paulsolt/dev/Photo-Slide-Show/Frameworks/Kiwi/Kiwi/KWItNode.m:41 #22 0x0261ae22 in -[KWExample runWithDelegate:] at /Users/paulsolt/dev/Photo-Slide-Show/Frameworks/Kiwi/Kiwi/KWExample.m:113 #23 0x02618c95 in -[KWSpec invokeTest] at /Users/paulsolt/dev/Photo-Slide-Show/Frameworks/Kiwi/Kiwi/KWSpec.m:105 #24 0x2010405b in -[SenTestCase performTest:] () #25 0x201037bf in -[SenTest run] () #26 0x2010792b in -[SenTestSuite performTest:] () #27 0x201037bf in -[SenTest run] () #28 0x2010792b in -[SenTestSuite performTest:] () #29 0x201037bf in -[SenTest run] () #30 0x201063ec in +[SenTestProbe runTests:] () #31 0x0072f5c8 in +[NSObject performSelector:withObject:] () #32 0x00002342 in ___lldb_unnamed_function11$$otest () #33 0x000025ef in ___lldb_unnamed_function13$$otest () #34 0x0000268c in ___lldb_unnamed_function14$$otest () #35 0x00002001 in ___lldb_unnamed_function4$$otest () #36 0x00001f71 in ___lldb_unnamed_function1$$otest ()
1. Add a new target with it's own unit tests. Creating unit tests with a "static library" template gives you "logic tests", while creating unit tests with a "iPhone application" gives you "application tests." The difference is that you can't use UIKit classes in logic tests, but you can in application tests.
2. In an application test, the runloop of the iPhone app starts, which means all the UIKit goodies are setup. The bad news is that it loads all the default state from your previous app runs. You might need to write some methods to cleanup or reset state. (GHUnit is nice because it's more sandboxed)
3. If you're using Kiwi you'll have to setup the Kiwi environment (library/header paths) again for the application tests.