سؤال

I'm unit testing a Mac App in Xcode 5 using the new XCTest framework. Specifically, I'm trying to test that a class implements an (as yet unwritten!) - (id)initWithStream:(NSInputStream)stream method. So I have the start of my test:

- (void)testInitWithStream
{
  // Should have an init method named initWithStream:
  XCTAssertTrue([[MYParser alloc]
                 respondsToSelector:@selector(initWithStream:)],
                @"'initWithStream:' not implemented.");

Which works fine; the test currently fails as expected. It's the next part, which attempts to run the as-yet-unwritten method, that's causing me grief:

  // Should return nil if no valid stream is passed
  XCTAssertNil([[MYParser alloc]
                  performSelector:@selector(initWithStream:)
                  withObject:nil], 
                 @"should get nil on 'initWithStream:' with no stream.");

Xcode gives me the error "PerformSelector names a selector which retains the object." I'm using performSelector:withObject: because attempting to call the selector directly results in an error that "No visible @interface for 'MYParser' declares the selector 'initWithStream:'."

My test suite has GCC_WARN_UNDECLARED_SELECTOR turned off, but these are errors, not warnings. How can I test the init methods of objects when the test needs to cover the situation where the method may not be implemented (even as a definition) yet?

The method may not be implemented yet because I'm writing my tests first; is this right, or should I be writing my class definitions first, then my tests, then the actual implementation? (I'm looking for consensus and best-practice on this point, not just opinion.)

هل كانت مفيدة؟

المحلول

If you are doing test first development, you don't need to test for respondsToSelector:@selector(initWithStream:). Directly calling initWithStream: in your test suite will at first not compile. This is your failing test that you should fix before writing new code. How do you fix it? By implementing the method:

- (instancetype)initWithStream:(id)stream {
    return [super init];
}

Your test now compiles, which is a little bit better than before. Running the test will fail though, because obviously the implementation doesn't do what you're testing for. Now write more code to make the test actually pass:

- (instancetype)initWithStream:(id)stream {
    if (!stream) {
        return nil;
    }
    return [super init];
}

Next, you can test for stream not being nil, which will fail so you write more code to fix it.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top