Say you’ve got a private method

-(NSUInteger)stackCount {
    return [self.myStack count];
}
@end

And you would like access to it in your test.

- (void)testAddNumberToStack {
    Calculator *calc = [Calculator new];
    [calc pushOperand:1.0];
    XCTAssertEqual(1, calc.stackCount);
}

You could expose it publicly in your header, but that would means exposing our privates (something we prefer to avoid). One neat thing I didn’t appreciate Objective-C could do was simply re-create the interface you want for your object under test in your test class, exposing the method you want to call, and then calling it from there.

@interface Calculator (Tests)
-(NSUInteger)stackCount;
@end

@implementation CalculatorTest

- (void)testAddNumberToStack {
    Calculator *calc = [Calculator new];
    [calc pushOperand:1.0];
    XCTAssertEqual(1, calc.stackCount);
}
@end

It may seem like cheating a bit. But because Objective-c is just a method based language of communication, we can define the message we want to send the object, and just send it assuming that when the tests runs, the method is going to be there.

Thanks to Mikael for showing me this trick. Means I can keep certain methods private, yet get access to them when I want for testing. Var kul!

Complete source

Calculator.h

#import <Foundation/Foundation.h>

@interface Calculator : NSObject
// operations
-(double)result;
-(void)pushOperand:(double)number;
@end

Calculator.m

#import "Calculator.h"

@interface Calculator()
@property (nonatomic, strong) NSMutableArray *myStack;
@end

@implementation Calculator

-(NSMutableArray *)myStack {
    if (!_myStack) _myStack = [NSMutableArray new];
    return _myStack;
}

-(double) result {
    return 0;
}

-(NSUInteger)stackCount {
    return [self.myStack count];
}

-(void)pushOperand:(double)number {
    NSNumber *operandNumber = [NSNumber numberWithDouble:number];
    [self.myStack addObject:operandNumber];
}

@end

Calculatortest.m

#import <XCTest/XCTest.h>
#import "Calculator.h"

@interface CalculatorTest : XCTestCase
@end

@interface Calculator (Tests)
-(NSUInteger)stackCount;
@end

@implementation CalculatorTest

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

- (void)testCreateEmptyStack {
    Calculator *calc = [Calculator new];
    XCTAssertEqual(0, calc.result);
}

- (void)testAddNumberToStack {
    Calculator *calc = [Calculator new];
    [calc pushOperand:1.0];
    XCTAssertEqual(0, calc.result);
    XCTAssertEqual(1, calc.stackCount);
}

@end