Skip to content

Running Tests

Jens Alfke edited this page Sep 27, 2013 · 7 revisions

Couchbase Lite uses my own oddball unit-test framework, whose API you can find in vendor/MYUtilities/Test.h. It isn't fully integrated with Xcode 4's nice test support, so you can't just choose the Product > Test menu command to run the tests.

How To Run The Tests

Tests run when an executable target launches; they're not a separate target the way Xcode's regular tests are. So you'll need to select a scheme that builds something runnable, like the existing "Mac Demo" or "iOS Demo".

Tests are enabled by command-line arguments whose names start with Test_. (If you don't know how to configure the argument list, see below.)

  • If a test case is implemented in the source code as TestCase(Foo) {...}, you enable it with argument Test_Foo. You can add any number of such arguments.
  • As a shortcut, you can enable all tests via the argument Test_All.
  • By default, the app will launch normally after the unit tests pass. To disable this you can add Test_Only.

Then run the target. Test output appears in the debugger console, of course. If an assertion fails, the test will log a message, raise an exception and exit. Subsequent tests will still run, though. At the end of the run you'll get a list of which tests failed.

Pro tip: As a shortcut to enable multiple tests, you can create an aggregate test that uses the RequireTest() macro (see below) to invoke the tests you want to run. Then you just have to enable the aggregate test.

Configuring The Server For Replication Tests

Some of the tests will replicate with a remote database. By default they look for a CouchDB server on localhost, which of course won't work when testing on an iOS device. You can override this and specify a custom server by setting the following environment variables at runtime:

    CBL_TEST_SERVER :    The base URL of the server (defaults to http://127.0.0.1:5984/)
    CBL_TEST_USERNAME :  The user name to authenticate as [optional]
    CBL_TEST_PASSWORD :  The password [required if username is given]
    CBL_TEST_REALM :     The server's "Realm" string [required if username is given]

If you're just using your development Mac as a server and it doesn't have a static hostname or IP address, you can use its Bonjour hostname, like snej.local. (See the Sharing system pref pane to find or configure this.)

How To Configure Command-Line Arguments and Environment Variables

  1. Press Cmd-Option-R, which is an optional form of the Run command that brings up the scheme's settings.
  2. In the sheet, click the "Arguments" tab.
  3. Click the "+" button below the "Arguments" list to add an argument (or multiple args separated by spaces, e.g. -Log YES).
  4. Click the "+" button below the "Environment Variables" list to add a variable.

Pro tip: You can temporarily disable these by unchecking them, so it's very easy to toggle tests on and off.

How To Write New Tests

Unit tests are basically functions, declared with special syntax:

    #import "Test.h"
    
    TestCase(Arithmetic) {
        CAssertEq(2 + 2, 4);
    }

This means you can put them anywhere; they don't have to go into separate files. I find it convenient to put small unit tests at the end of the source file that implements the feature being tested. That means I don't have to jump between files so much while testing, and the tests can call static functions and internal methods without having to jump through hoops. But for larger test suites it's cleaner to make a separate source file (I've got several of these, named like "XXX_Tests.m".)

Tests use a custom set of assertion macros. This isn't strictly necessary -- you can use NSAssert if you want -- but I like mine better. Their names start with Assert… -- There's Assert, AssertEq (for scalars), AssertEqual (for objects), etc. You can see them all in the header Testing.h.

By the way, you can use these assertion macros anywhere in the code, not just in unit tests. I sprinkle in plenty of them.

A test can require another test as a precondition. That way it can assume that the things already tested work and doesn't have to add assertions for them. To do this, begin a test with one or more RequireTest(Foo) calls, where Foo is the name of the test to require. (Don't put the name in quotes.)

Clone this wiki locally