Search code examples
swiftobjective-cxcodeunit-testingxctest

Xcode unit test compare two array parameters


I have a flow in my app that inserts Response objects into an array, This is the response object:

@interface AppResponse : NSObject

@property (nonatomic, assign) MotSDKState  state;
@property (strong, nonatomic) NSError * _Nullable error;
@property (nonatomic, assign) NSInteger errorCode;
@property (strong, nonatomic) NSDictionary * _Nullable response;

@end

I want to check at the end of the flow if the array is correct, so I create a test:

var err = AppResponse()
err.errorCode = 1000
err.state = .failed
let expectedArray = [err]
XCTAssertEqual(self.responsesArray, expectedArray)

I also tried with Nimble:

expect(self.responsesArray).to(equal(expectedArray))

And I get for both of them this unit test failed error:

error: -[****.**** *****] : failed - expected to equal <[<Appesponse: 0x600003288240>]>, got <[<Appesponse: 0x6000032948d0>]>

Any idea what is the problem? how I can compare two arrays of objects?


Solution

  • Caveat

    I'm assuming we're seeing most of the AppResponse code, and that you haven't implemented an [AppResponse isEqual:] method. If you have:

    • this answer doesn't apply
    • you possibly should include it with the question

    Answer

    Consider this Swift code (which maybe should have been the first thing you tried):

    let a = AppResponse()
    let b = AppResponse()
    
    print(a == b) // prints "false"
    print(a == a) // prints "true"
    
    

    Behind the scenes, these last two lines are equivalent to:

    print(a.isEqual(b))
    print(a.isEqual(a))
    

    which is the Objective-C equality method, [NSObject isEqual:] (see here).

    The default implementation of that method just compares the pointers to the objects, not their contents. As we showed above, it will always be false unless you compare literally the same object.

    If you want these comparisons to work, you need an [AppResponse isEqual:] method comparing AppResponse objects by their properties. Because you are using these in arrays, I think that also implies needing a compliant [AppResponse hash] method. There are many guides to help you with that, e.g. this one.