Testing C++17 Projects in Xcode With XCTest

The vast majority of development I perform is in C++17 on an Apple Mac Computer using Xcode. For a while now, I have been using Catch2 as my Unit Testing framework, and its absolutely excellent. But its not integrated into the Xcode IDE and I wanted the ability to use Xcode’s excellent testing and test debugging tools to improve my productivity and workflow.

In this post I will show you how to set up a simple standard C++17 library project in Xcode 10 and then add XCTests to it.

You can find and download the sample project from Github at HiltmonLibrary-with-XCTest.

Setting Up the Library

Create the Project

I am going to start with my standard, designed for cross platform, C++17 library project. In a terminal, lets create the folders needed:

cd Projects
mkdir HiltmonLibrary
cd HiltmonLibrary/
mkdir -p doc include/hmlib src test
git init


NOTE: hmlib above is the namespace I will be using for the standard library project.

Now we will create the Xcode Project:

• In Xcode, choose File / New Project.
• Select macOS at the top, then Library and click Next.
• Fill in the project details, choose C++ and click Next.
• Select the Project Folder we just created, then click Done.
• Close the project Xcode window. Do this because we need to move some files around.

The next two steps clean up that which we just created:

• In Finder, go to the Project Folder.
• Drag and drop the *.xcodeproj up a level, then delete the new folder (HiltmonLibrary under HiltmonLibrary).
• Double-click to open the project in Xcode.
• Right-Click on the red folder and select Delete to remove the Xcode created folder and files.
• Right-click on the Project (at the top of the tree) and select Add files to “HiltmonLibrary”….
• Press CMD-A to Select all, then click Add.

The standard library template is almost ready.

Update for C++17

Lets make it C++17 compliant, add extra warnings and expose inline methods from the library:

• Click on the Project Name at the top to see the project settings panel.
• Click on Build Settings, then type C++ in the search box. Change the C++ Language Dialect to C++17 [-std=c++17].
• Search for Inline and change Inline Methods Hidden to No.
• Search for Other Warning and double-click to the right of Other Warning Flags. Click + to add the following flags:
• -Wall
• -Wextra
• Search for Search and double-click to the right of Header Search Paths. Click + to add the following flags:
• $SRCROOT/include/hmlib • /usr/local/include • While there, double-click to the right of Library Search Paths. Click + to add the following flags: • /usr/local/lib If you clear the search, and select Customized at the top, you should see something like this: Add Project Code And finally, lets add our first items to test. We’ll create a utilities namespace to host some string manipulation functions to test: • Right-click on the src folder and choose New File or select the src folder and hit CMD-N. • Choose C++ File and click Next. • Create the C++ File, in this case string_utilities, make sure create header file is checked, and click Next. • Make sure it goes in the src folder and that the target is checked (in my case HiltmonLibrary, and click Create. • Finally, drag and drop the .hpp file under the include/hmlib folder. Ok, lets create some code to test, say a function that converts a string to lowercase. In string_utilities.hpp: In string_utilities.cpp: Compile with CMD-B and the library should compile OK. If you expand the Products folder, you should see the compiled library. Note that a bug in Xcode 10 means that you may need to restart Xcode for it to stop showing as red. Setting Up the Tests Great, we have an awesome library, how do we go about testing it? Create and integrate the Test Target • Press CMD-6 to show the Test Navigator (or select the icon to the right) • At the bottom, click the plus and choose New Unit Test Target… • I prefer to make a strong name for test targets, so I named mine TestHiltmonLibrary. • Make sure Objective-C is selected as the language and that the test target is your library (in my case HiltmonLibrary) • Click Finish to create the target Xcode helpfully shows you the new Target configuration page. Update for C++17 Lets bring it up to C++17 standard (same as for the main library project): • Click on Build Settings, then type C++ in the search box. Change the C++ Language Dialect to C++17 [-std=c++17]. • Search for Inline and change Inline Methods Hidden to No. • Search for Other Warning and double-click to the right of Other Warning Flags. Click + to add the following flags: • -Wall • -Wextra • Search for Search and double-click to the right of Header Search Paths. Click + to add the following flags: • $SRCROOT/include/hmlib
• /usr/local/include
• While there, double-click to the right of Library Search Paths. Click + to add the following flags:
• /usr/local/lib

And to standardize the project:

• Drag and drop the Info.plist and TestHiltmonLibrary.m file to under the tests folder.
• Delete the TestHiltmonLibrary folder.

The reconnect the Info.plist

• Click on the Project name in the Project Navigator, and choose the test target.
• Change the Info.plist File entry to test/Info.plist.

Integrate with the Main Library Project

And finally, hook it all up:

• Click on Product, Scheme, Edit Scheme…, right-click on the scheme in the tool bar and choose Edit Scheme, or press CMD-<.

• Make sure the scheme selected is the Library scheme (HiltmonLibrary), not the Test scheme (TestHiltmonLibrary) in the top left of the sheet that shows up.
• Click on Test on the left.
• Click the plus at the bottom to add a test target and choose the test target (now add TestHiltmonLibrary).
• Click Close when done.

Lets Compile and Run the tests to see what happens. Press CMD-U. Xcode will:

• Compile the main Library
• Compile the test Target
• Run the tests
• Switch you to the Test Navigator

Since no tests have been created, it should have no failures.

Thats it, the hoops have been jumped through to set things up. From now on, all you need to care about is developing your project code and your new tests.

Let’s add our first C++17 tests.

Rename the default file TestHiltmonLibrary.m to better reflect the tests being run, in this case we’re testing our String Utilities, so rename it to TestStringUtilities.mm

NOTE THE FILE EXTENSION CHANGE FROM .m TO .mm. This is the secret, it tells Clang to compile the file as Objective-C++ which is how we get XCTest to talk C++.

• Include the header of the class being tested
• Remove the current functions and add the test function

FOR XCTEST TO WORK, THE FUNCTION MUST START WITH test.

The XCTAssert macro is used to evaluate an expression and pass if true.

The final file should look like:

Press CMD-U to run the tests. Xcode will run the tests and put a bezel up that tests have passed and puts a green checkmark next to the test functions that passed.

Lets create a failing test:

• Add to the testCaseChanges code:

And press CMD-U. Xcode compiles the tests and fails because the toUpper function has not yet been written. As expected.

• In string_utilities.hpp, add:
• In string_utilities.cpp, add:

Ok, lets test again. Press CMD-U. Tests succeeded.

Lets add another class to test. But this time, lets make it header-only so under normal circumstances, the library compiler will ignore it.

• Create numeric_utilities.hpp (Header File only) under include/hmlib as:

Since this is a header-only file, the compiler will pretty much do nothing with it when building the library. So let’s add a test to get it to compile and see it this mad round code works.

• Go to the test Navigator. Click the plus and choose New Unit Test Class….
• Name it TestNumericUtilities.mm. REMEMBER the .mm extension to get C++.
• Clean it up and make it ready for the test.
• Include the header file #include "numeric_utilities.hpp".
• The add a test function and some test Asserts.

The file will now look like this:

Press CMD-U to compile the Library and run the tests.

Since the header file is included in the test compile, the compiler looks at it (and will fail if there are any issues).

If the compilation succeeds, it will run the tests.

C++17 Tests with XCTest in Xcode

And there you have it, a standard C++17 project, editable and compilable in Xcode, with single key access to tests and all the IDE features of Xcode to help debug and analyze your project.

A few tricks you can add:

• Setting a breakpoint in a test case will work as expected. Xcode will stop testing there and you’ll be able to use all the debugger tools in Xcode to see what is going on.
• Hover over a Test Class in the Test Navigator or place your mouse on any line, and you will see a small right triangle icon with a circle appear. Click that to run just that one test class. That way you can work an individual test until such time as it works without having to wait for and run all test cases.

Happy Testing C++17 in Xcode with XCtest.

Reminder: You can find and download the sample project from Github at HiltmonLibrary-with-XCTest.