How do I set up target logic tests in a Xcode 4.5 Command Line Tool?

Unable to get unit tests configured for a specific scenario. Here is what I am trying:

  • In Xcode 4.5, I created a simple OSX “Command Tool” application project (Foundation).
    Please note that Xcode does not provide the ability to add unit tests to the Command Line Tool project automatically - therefore, please do not offer to tick the checkmark; it is not: - /

  • In my project, I created a trivial sample class that I would like to test; for example, "Form."

  • I followed the instructions in the Apple Xcode Device Test Guide for Setting Up Unit Testing in a Project :

    • I added the unit test target to my project and

    • I edited the Test scheme to run tests for a new target.

  • In the test project implementation (.m) file, I added imports for Shape.h and the code in the setUp() method to create an instance of the form and assign it an instance variable.

At this point, I decided to see if things would be built, and if the default test would work as before. However, when I selected Product ... Test from the menu, the build failed with the following error:

 Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_Shape", referenced from: objc-class-ref in ExampleTests.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) 

Interpretation of this error is not a problem. I understand that the unit test goal is not related to the binary version containing the Shape implementation. However, I have not tested Xcode unit testing and target configuration yet. So:

What do I need to do to link the test link to the command line result? Is it possible to connect to the executable from the command line from unit test? Apple documentation applies to regular OSX applications ( *.app ) and iOS applications, and this is not the case.

I have business logic classes that I would like to develop in the command line tool (for starters), so I would like to understand what I need to do to get the unit test target running in the "Command Line Project". Thanks!

(ps Please note that I am not interested in running my unit tests from the command line - Stack Overflow has already offered "similar" questions on how to do this - but rather unit tests in the "Command Line Tool" work, the type of the project is still inside Xcode .)

+8
unit-testing xcode command-line-tool linker-errors
source share
3 answers

I have identified a workaround that I find suitable and that has no significant flaws other than the added purpose.

In short: the solution involves adding a static library target to take advantage of Xcode's ability to create and run unit test code around that target. The command line tool tool then delegates to the static library, where an alternative main() -like function is defined and called by the main() input point. The command line tool does not contain non-trivial code, so the unit test target can access everything that needs to be checked.

Here are the steps:

  • From an empty Xcode, from the menu, select File ... New Project.

  • In the dialog that appears, select OS X ... Application ... Command-line tool. For this example, I assume it is called SampleCmd.

After creating the basic command line tool tool:

  • From the menu, select File ... Create ... Target.

  • In the dialog that appears, select OS X ... Framework and Library ... Cocoa Library. For this example, I assume it is called SampleCmdLogic.

  • Select the Static type, so the command line tool will remain a standalone executable.

  • Make sure the Enable Unit Tests box is checked.

After creating the static library project:

  • Copy the main() function from main.m to SampleCmdLogic.m , replacing the @implementation block. (This file will contain only the main entry point. Other files can be added for Objective-C classes, etc.) Rename the libMain() function.

  • In SampleCmdLogic.h add the declaration for the new libMain() , replacing the @interface block:
    int libMain(int argc, const char * argv[]);

  • In the main.m command-line main.m add #import "SampleCmdLogic.h" at the top.

  • In the main.m command-line main.m change the entire contents of the real main() function to:
    return libMain(argc, argv);

The code is now ready, but the binding steps are required:

  • In the project settings for SampleCmd in the SampleCmd Phases section, expand Target Dependencies and add (+) SampleCmdLogic as the dependency.

  • In the project settings for SampleCmd , in the "Build Phases" section, expand the "Link to Libraries" link and add (+) libSampleCmdLogic.a

Now everything is ready. When you navigate to the SampleCmd target and select Product..Run from the menu, the assembly should be successful and output generated as expected. When you go to the SampleCmdLogic target sample and select Product ... Test from the menu, the assembly should be successful and unit tests will be performed. The only issue in question will be the original default unit test error inserted by Xcode in SampleCmdLogicTests.m . Expected.

From now on, add all the logical and relevant tests to TargetCmdLogic. The goal of SampleCmd should remain trivial and provide only the entry point of a command line tool.

+13
source share

As a rule, there are several additional steps to add a target to an application project - in particular, setting up a Bundle Loader and a test host, as I describe in https://stackoverflow.com/a/3/2127/ .

But when I made them using the command line tool and tried to run the tests, all that was done was to run the tool. For the application, it goes through the application launch phase, introducing a test suite into the running application, and then performs the tests. But these steps do not apply to command line tools.

Therefore, instead of an embedded test suite, you will need a second command line tool that runs your tests. Then set your classes so that they aim at the test tool, as well as at your real tool. gh-unit and google-toolbox-for-mac both follow this model, so I would try them.

+3
source share

It seems that the most immediate problem is that Shape not part of the new test target. Try adding Shape.m to the target:

  • Click on Shape.m in the Project Navigator
  • Open the Utilities view (View → Utilities → Show Utilities)
  • In the Target Membership section of the Utilities view, make sure that both applications and test objects are checked.

I do not know if this will end with your problems with your setup, but it seems like a likely candidate for your most immediate problem.

+1
source share

All Articles