Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding XCTest unit tests to existing app doesn't work

I've added tests (XCTests) to an existing C++ command line app in Xcode 5

  • via Test Navigator > (+),
  • changed the extension of the test class to .mm,
  • added the XCTest framework to the project.

All compiles fine. Now running the tests just gives me a 'Test failed' message, nothing in the console and neither green nor red lights in the Navigator (i.e. no tests executed).

Starting with a fresh Xcode 5 project and changing the extension of the test class to .mm just works fine so I'd assume it's not just about lacking support for Objective-C++ in XCTest.

Even with a plain, vanilla test target added to the existing C++ project the tests fail before ever running.

Any more gotchas to watch out for when adding XCTests to existing (Objective-)C++ targets?

Update #1

With Xcode 5.0.2 (on 10.8.5) xctest now crashes in the same scenario with an

*** NSTask: Task create for path '/Users/XXX/Library/Developer/Xcode/DerivedData/RM_Next_Gen-gpihzjouhxvifqcslmywktktizer/Build/Products/Debug/YYY Tests.xctest/Contents/MacOS/YYY Tests' failed: 22, "Invalid argument".  Terminating temporary process.
objc[3478]: GC: forcing GC OFF because OBJC_DISABLE_GC is set
*** multi-threaded process forked ***
like image 391
Jay Avatar asked Oct 03 '13 09:10

Jay


2 Answers

Turns out it was a command line C++ project which apparently isn't currently supported by XCTest. Testing the C++ code from an Objective-C(++) project works just fine..

Just hoping for better documentation of XCTest at some point in the (near) future.

like image 197
Jay Avatar answered Sep 20 '22 21:09

Jay


I couldn't find any documentation on using XCTest to test code that is not Objective C (C / C++). I am wanting to test a command line C project, and I was concerned that your answer suggested that doing this is unsupported by Xcode. I'm a novice to XCTest and TDD, but I thought others might appreciate what I discovered.

I created a New Project > Command Line Tool, based on C. Project is called foo; Xcode will call the target foo by default too.

-Files created: main.c

Add test target by going to Test Navigator > (+) > New Test Target. Call the target fooTests. Xcode will create this target and an example test within it (all within the file called fooTests.m). The example test will be called testExample and it will contain the test function below:

- (void)testExample
{
    XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
}

If you run the tests now (either from the Product>Test menu item or ⌘U) then the test will fail (it's supposed to). For the sake of brevity, I won't go through the TDD cycle, but simply list the files and contents that need to be added to test functions that are not within Objective-C classes.

Let's say that we have a function that we want to test, called bar(), and called from main.c. Go to the project file explorer and add a new header file called bar.h. Add the function prototype:

int bar();

If you want to use XCTest to test a function, it can't be in main.c, so add it to a new C Source file called bar.c. Important: when you add the file, you must add it to the target foo and to fooTests. if you don't add it to fooTests then when compiling the tests the linker won't find the function.

int bar() {
    return 0;
}

Within fooTests.m, add the include:

#include "bar.h"

You can now refer to any function contained in bar.h within your tests. Now create 2 unit tests, one that will fail, the other that will pass.

Delete the method testExample and replace with the following code:

- (void)testBarWillFail
{
    int rc = bar();
    XCTAssertTrue(rc == -1, @"Expected rc==-1, rc==%d", rc);
}

- (void)testBarWillPass
{
    int rc = bar();
    XCTAssertTrue(rc == 0, @"Expected rc==0, rc==%d", rc);
}

Running the tests will produce the following in the debug window:

Test Suite 'All tests' finished at 2014-01-12 13:38:45 +0000.
Executed 2 tests, with 1 failure (0 unexpected) in 0.000 

Within the Issue Navigator pane you'll see:

file: /foo/fooTests/fooTests.m: test failure: -[fooTests testBarWillFail] failed: ((rc == -1) is true) failed - Expected rc==-1, rc==0

This is all as expected! Repeat the process with all other C code you wish to test.

If anyone knows a better way of doing this then I'd be delighted to hear it!

like image 42
John Avatar answered Sep 19 '22 21:09

John