84

I added a simple unit test to test my string extension. But it fails. What I am I doing wrong here?

From what I know XCTAssertEqual is testing value and not the object itself?

The third line btw, says the string are equal, but XCTAssertEqual says they're not.

- (void) testInitialsFromFullname {
    NSString *firstNickName = @"Mike Kain";
    NSString *expectedResult = @"MK";
    NSLog(@"Equal:%@", [[firstNickName initialsFromString] isEqualToString:expectedResult] ? @"YES" : @"NO");

    XCTAssertEqual(expectedResult, [firstNickName initialsFromString], @"Strings are not equal %@ %@", expectedResult, [firstNickName initialsFromString]);
}
GingerHead
  • 8,130
  • 15
  • 59
  • 93
Konrad77
  • 2,515
  • 1
  • 19
  • 36
  • 2
    This was a perfectly reasonable question, and I ran into the same issue when I first started with XCUnit. The accepted answer helped as well. – Michael Teper Oct 03 '14 at 15:58

3 Answers3

177

From the documentation of XCTAssertEqual:

Generates a failure when a1 is not equal to a2. This test is for C scalars, structs and unions.

You should use XCTAssertEqualObjects (which uses isEqual: internally) or something like:

XCTAssertTrue([[firstNickName initialsFromString] isEqualToString:expectedResult],
              @"Strings are not equal %@ %@", expectedResult, [firstNickName initialsFromString]);
Arek Holko
  • 8,966
  • 4
  • 28
  • 46
  • 10
    It seems that if you XCTAssertEqualObjects() two NSString objects they are compared with isEqualToString: automatically. – Cla Mar 04 '15 at 11:31
  • 1
    It uses `-isEquals:` under the hood all the time, but for `NSString` `-isEquals:` executes well-known `-isEqualToString:`. For instance, `NSNumber` implementation of `-isEquals:` method uses `-isEqualToNumber:`. – Ossir Dec 11 '15 at 07:25
  • 3
    Unfortunately despite still being in the docs, as of Xcode 7.2 XCTAssertEqualObjects is no longer available. – Max MacLeod Jan 13 '16 at 10:33
  • 1
    XCAssertEqual(a, b) works just fine in XCode 7. This answer is not correct anymore. – MdaG Sep 07 '16 at 11:50
  • 2
    XCTAssetEqualObjects is available in Xcode 8.0 and works for comparing NSStrings. – Keller Oct 23 '16 at 20:00
  • 1
    Using `XCTAssetEqualObjects` is better because if the test is failed, it will throw exactly the wrong string. `XCTAssertTrue` throws just only: "Oh it's not true" – Phu Nguyen Apr 03 '18 at 08:40
  • This is actually a test smell. Don't do this. – timbre timbre Mar 16 '23 at 16:43
16

I've just had a similar issue which might help someone.

I have a Float extension function which returns a string. The following test fails:

testValue = 0.01
XCTAssertEqual(testValue.formattedForCost(), "0,01 €")

With the following message:

Assertions: XCTAssertEqual failed: ("Optional("0,01 €")") is not equal to ("Optional("0,01 €")")

Which is rather annoying. However I discovered if I change my test to use the unicode no-break space character:

XCTAssertEqual(testValue.formattedForCost(), "0,01\u{00a0}€")

It passes.

Leon
  • 3,614
  • 1
  • 33
  • 46
3

Objective-C Comparing strings

- (void) testStringComparison {
    NSString *first = @"my string";
    NSString *second = @"my string";
    
    NSMutableString *firstMutable = [NSMutableString stringWithString:first];

    //== comparing addresses of the objects(pointer comparison)
    //`first` and `second` has the same address it is a compiler optimization to store only one copy
    XCTAssertTrue(first == second);
    XCTAssertFalse(first == firstMutable);
    
    XCTAssertEqual(first, second);
    XCTAssertNotEqual(first, firstMutable);
    XCTAssertEqualObjects(first, firstMutable);
    XCTAssertTrue([first isEqualToString:firstMutable]);
}
yoAlex5
  • 29,217
  • 8
  • 193
  • 205