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
May 26, 2015 @ 19:12:28
cool suggestion. you can also create a .h file with your methods and import them into your .m file, and your test class.
Oct 23, 2015 @ 20:39:27
thank you
Jun 25, 2018 @ 00:07:40
Thank you!