test targets and renaming test classes

So ... I renamed a test class in my test cases.

Then the test target started to fail:
unable to open executable '/Users/smcphee/Library/Caches/appCode10/DerivedData/<product>-6322e2cf/Build/Products/Debug-iphonesimulator/<target>Tests.octest/<test class>'
Can't generate the DSYM and the linker fails.

I tried to then reconfigure my test target. This makes it worse.

This is not strictly AppCode - Xcode has the same basic result.

Then, I just revert all my project back to the last head version.

Tests still fail as above. The "missing" test class (orginal name) still exists. Appcode and Xcode. Project totally reverted to the way it was pre- test class rename! My tests permanently busted!

What's going on? Is there something **external** to the project directory that controls the configuration of the test cases?

I'm using Appcode because I'm a former Java programmer (10+years).  And while Appcode is way nicer than Xcode it seems to me that the whole way Apple has designed the project structure and stuff is like some blast from the 1980s. Its like something Oracle would design.  It's horrible and crippled and on what planet does renaming a test class destory your project configuration?!.

But does anyone have any ideas on how I might fix it?

Thankyou.

oh .. project code (which did work) is here https://github.com/scotartt/LatinLookupTool

[edit: no, it doesn't .. the whole test cfg is missing which must be the issue .. but adding back in according to apple's instructions results in a test scheme that has no execution target? ... how the hell do i fix that?]

8 comments

Scot,
first, check the Run Configuration in AppCode, it should be OCUnit configuration with the corresponding class/test method specified.
If everything is correct, try cleaning the derived output folder (~/Library/Caches/appCodeXX/DerivedDir, and rebuilding the app from the scratch.

0

Thanks Anton I will have a look at that and tell you how I get on with it.

0

I've been reverting my project repeatedly back to a clean version with no unit testing target, classes or schema configurations (in the project file?)

But even after I cleaned out that "cache" location that you mention AppCode still thinks I have a Testing Group in the Project, with "missing" files in red. These are not in the project.pbxproj file. Here's what it looks like:

Screen Shot 2013-03-15 at 21.58.41 .png
If I clone the project out from its git hub repository (listed in my original post) into a new directory it's fine and reads it fresh and apparently OK.

So the question is: apart from the cache location that you listed, and the project.pbxproj file what other locations/files does AppCode (and/or Xcode) use to "configure" the project? For example a freshly cloned repository from github lacks the files "project.xcworkspace" and "xcuserdata" that are in the project bundle dir once the project has been opened into the IDE (into Xcode? Appcode? either? - loading a clean project into AppCode seems to create the "xcuserdata" file, certainly). Clearly git's not comitting these files (I created the repo on github as an Xcode project and those files are in .gitignore).  I guess they may contain something that alters either AppCode or Xcode's behaviour which is the cause of my issues (i.e. old, apparently "sticky" and stale project configuration).

I also see a ".idea" directory (empty) likewise in a clean, but once loaded into AppCode, checkout.

I hate magic files for this reason. Appcode ought to have a "clean out this project of non-source controlled configuration" option which empties the cache and trashes these files or something. I think what's been happening is that I've been "reverting" the one project dir when my attempt to fix my problems has failed ... but because these files are left there it "inherits" the left over bad configuration which is reactived when I try to apply the fix. Thus is looks like what is supposed to work, won't. And when I saw the above .. it clicked that //there must be magic IDE files in the project//  ... I am just trying some stuff on a clean check out and I got past my *first* point of failure (although I haven't restored all my tests just yet so not out of the woods quite at this point!).

Is there a guide to these magic files and what they do? So that we know which file to delete under what circumstance?

thanks
scot

0

Scot,
could you please shortly restate the current problems that you have?
Thanks.

0

OK I've been able to narrow it down to what starts the grief although I've not been able to get rid of it.

Bear in mind these are tests I originally developed in AppCode in order to build my basic data components so they once passed (until I tried renaming the test class and found myself in a world of hurt).

I created a brand new Test Target in Xcode according to the relevant Apple page that's here: - http://developer.apple.com/library/mac/#documentation/developertools/Conceptual/UnitTesting/02-Setting_Up_Unit_Tests_in_a_Project/setting_up.html

I get a "test.h" interface and a "test.m" impl which when run in Appcode or Xcode runs but fails (because STFail("tests not implemented")). Removing the STFail line causes tests to pass (hey this TDD thing is easy, I have a green bar already!! ;-) )

I then add a couple of things to my test.h to  start to make it have the the interface I need, here it is in toto:

//
//  LatinOnlineWordLookupTests.h
//  LatinOnlineWordLookupTests
//
//  Created by Scot Mcphee on 15/03/13.
//  Copyright (c) 2013 Scot Mcphee. All rights reserved.
//

#import <SenTestingKit/SenTestingKit.h>
#import "OWLMorphData.h"
#import "OWLMorphDataObserver.h"

@interface LatinOnlineWordLookupTests : SenTestCase <OWLMorphDataObserver>

@property OWLMorphData *morphData;

@end


Then I add some things to my implementation so it looks like this:

//
//  LatinOnlineWordLookupTests.m
//  LatinOnlineWordLookupTests
//
//  Created by Scot Mcphee on 15/03/13.
//  Copyright (c) 2013 Scot Mcphee. All rights reserved.
//

#import "LatinOnlineWordLookupTests.h"

@implementation LatinOnlineWordLookupTests
    BOOL wasRefreshed = NO;
    BOOL wasError = NO;
    @synthesize morphData;

    - (void)setUp {
        [super setUp];
        //[self setMorphData: [[OWLMorphData alloc] init]];
    }

    - (void)tearDown {
        [super tearDown];
    }

    - (void)testNothing {
        STAssertEquals(0, 0, @"0 must equal 0");
    }

#pragma LatinMorphDataObserver protocol methods
    - (void)refreshViewData:(OWLMorphData *)latinMorph {
        wasRefreshed = YES;
    }
    - (void)showError:(NSError *)error forConnection:(NSURLConnection *)connection {
        wasError = YES;
    }
    - (void)showError:(NSException *)exception1 forSearchTerm:(NSString *)searchTerm {
        wasError = YES;
    }

@end



this runs and passes (hey, 0==0, who would have thought?) ...

But see that one line in in setUp() ... where I initialise the class I want to test? If I uncomment it, I get ...

unable to open executable '/Users/smcphee/Library/Caches/appCode10/DerivedData/LatinOnlineWordLookup-dccf1f46/Build/Products/Debug-iphonesimulator/LatinOnlineWordLookupTests.octest/LatinOnlineWordLookupTests'
The following build commands failed:
Ld /Users/smcphee/Library/Caches/appCode10/DerivedData/LatinOnlineWordLookup-dccf1f46/Build/Products/Debug-iphonesimulator/LatinOnlineWordLookupTests.octest/LatinOnlineWordLookupTests normal i386
GenerateDSYMFile /Users/smcphee/Library/Caches/appCode10/DerivedData/LatinOnlineWordLookup-dccf1f46/Build/Products/Debug-iphonesimulator/LatinOnlineWordLookupTests.octest.dSYM /Users/smcphee/Library/Caches/appCode10/DerivedData/LatinOnlineWordLookup-dccf1f46/Build/Products/Debug-iphonesimulator/LatinOnlineWordLookupTests.octest/LatinOnlineWordLookupTests
Build Finished with Error: 65

(BTW: tip -- it would be nice to be able to copy more than one of those lines at a time from the "Messages" window)

Of course, in the app itself I can initialise the class just fine and it actually works, because I wrote the class initially with TDD. I'm just trying to now restore the ability to run new tests ...

This was all done from a "clean & fresh" checkout of my project to bypass the "magic files" not in the repo.

XCode ... same behaviour ... so I realise it's probably a project files setup issue ...

0

I managed to fix it ... at least I made it work. After this morning's Xcode update, I tried for the 10th time to create a tests target and configure the Unit Tests.

I got a whole bunch of errors in Appcode (Xcode is really dumb at showing errors) that indicated a @protocol had some issues with it's reference to the object it observes (MorphData) ... like a circular reference (MorphData accepts a MorphDataObserver and calls methods when success or failure occurs, but passes 'self' as reference to the method as one of the arguments).

Therefore, adding

@class OWLMorphData;


to the protocol file made it link correctly (although it always built properly to run in the non-test scenario).

The linking errors I was getting at run time in the tests must have been related to that ... as the test implemented the callback protocol and using a successful or failed call back to drive the results of some of the tests. This was

I think the Xcode update to 4.6.1 this morning must have changed something to make this code problem explicit? Yesterday it was saying "the project won't link" whereas today its was indicateing a compilation issue with the protocol file (still much easier to see the error in Appcode)

0

Scot,
thanks for the update, we are glad that you've resolved the problem.
Though, we still don't quite get what issues you had had; if there is something that appcode could help with in such problematic situations, we'd appreciate a request with project example.

0

The main problem I was having is the tests did not link (link, as in the linker, you know, compile then link), or they failed at runtime, because of the missing @class directive at the the top of the protocol.

  1. Protocol.h -> specifies a call back method with an Interface as an argument.
  2. Interface.h -> when a condition is met, call a method on the protocol implementation, passing itself as an argument
  3. Interface.h had an #import protocol.h directive.
  4. Protocol.h didn't have anything other than a reference to the interface type in a method it declared.
  5. In the project there was a view controller that implemented the protocol but neither xcode nor appcode ever complained and everything compiled and linked.
  6. When I added the new test target and the  scheme to run the tests, everything was OK if used the default test stub that Xcode creates.
  7. But when in the test I reference the real object to test, the linker/compiler complained and would not compile/link the code. There weren't any errors in the IDE to say "this line here is busted"; just a stack of output as I posted above. (I never saved one of these busted projects, because at this point I'd roll the whole thing back and try again)
  8. However, when I upgraded Xcode to 4.6.1, which happened late last week, and did all the steps as above, the compiler was suddenly telling me about the cyclic dependency issue between Protocol.h and Interface.h in a clear way; and AppCode clearly marked the issue. I don't know if that was incidental to the upgrade, I suspect not, but you'd know better.
  9. Then I referenced the Interface type from with the Protocol.h with an "@class Interface" (the way yo're supposed to).
  10. At that point I could load the instance of Interface in the tests and they would run.


Why this didn't occurr in the main target, I don't know, but may be because of the way the Test Target refers to the standard Target.

protocol method:

- (void)refreshViewData:(InterfaceName *)theInterfaceSelf;


interface implemenation:

[self.protocolinstance refreshViewData:self];


There's some further background - I once had running tests, at an earlier point, I had a test target that ran just fine. However but I renamed the directory the classes were in, and in the process of fixing that, the tests stopped working, because as I discovered the name of the "Group" in an Xcode project is only loosely tied to the Directory the files are put in. So to simplify my life, I removed the tests from the project, intending to add them back later. However in the meantime I implemented this protocol with the cyclic dependency.

If you ask me know, what one thing could AppCode that would make my life / this problem easier? It would be this one:

Implement a refactoring that renames the Group, AND the Directory the group's files are in.

Probably I screwed the project up trying to manage the process of renaming the directory. The "official" instructions (edit the project file with a text editor) have to be the dumbest thing I ever heard. And it's not as simple as people make out ... you have to know a bit about the project file's structure (this week I learned more about that then I ever wanted to!). In ten + years of development, I never once edited a IntelliJ project file nor Eclipse .project/.classpath (OK, I did once or twice edit a .classpath file, but it's freaking obvious when you look at one). Here I am three/four weeks into learning myself Objective-C for iOS and I'm far more familiar with the ugliness inside the IDE's project file than I really want to be.

Sorry about the rambling. more features that would be great:

Create a Test Target and Scheme in AppCode rather than having to use Xcode. Perhaps some more automated set up of its settings rather than a long step-by-step editing procedure as found in the official Apple instructions. "Create Test Target" -> enter name of test target -> all set up! (as the default values are entirely predicable if you look at the procedure that Apple give!).


A really nice way to view and change the project file's settings; rather than having to use Xcode.


Maven or Gradle style functionality for Objective-C.

thanks for putting up with me.

Scot

0

Please sign in to leave a comment.