Singletion设计模式在cocoa中被广泛使用。在我们平时写App代码时也经常会将一些工具类,管理类设计成Singletion。Signletion通过一个类方法返回一个唯一的实例,与我们平常通过实例化生成一个个实例的场景有所不同。如果我们要stub一个Singletion的类的实例方法,那么这个Signletion的类初始化方法(eg:sharedMange())必须返回一个mock对象。因为只有mock对象才可以做stub操作。那么我们应该如何mock我们的Singletion呢,我们通过下面的例子一步步分析解决这个问题。
Singleton场景
比如我有一个Singleton的类(DemoStatusManage),他有一个实例方法currentStatus会返回一个1-100的随机数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
@interface DemoStatusManage : NSObject + (instancetype)sharedManage; - (int)currentStatus; @end @implementation DemoStatusManage { NSInteger _status; } + (instancetype)sharedManage { static dispatch_once_t once; static DemoStatusManage *manage; dispatch_once(&once, ^{ manage = [[DemoStatusManage alloc] init]; }); return manage; } - (instancetype)init { self = [super init]; if (self) { _status = 0; } return self; } - (int)currentStatus { return [self getRandomNumber:1 to:100]; } -(int)getRandomNumber:(int)from to:(int)to { return (int)(from + (arc4random() % (to - from + 1))); } @end |
然后在我的另外一个类中会去调用这个Singletion的currentStatus方法,并且将返回的数据渲染到另外那个类的label文案上。
1 2 3 |
- (void)updateStatusNumber { self.statusLabel.text = [NSString stringWithFormat:@"%ld",(long)[[DemoStatusManage sharedManage] currentStatus]]; } |
这是一个很简单的Singletion场景,但是在测试updateStatusNumber
这个API的时候由于依赖到了外部的DemoStatusManage的currentStatus方法,而且这个方法返回的是一个随机数值,所以我们必须mock掉Singletion,然后再stub调currentStatus方法,让这个方法返回我们期望的一个固定值。
应该用OCMock的哪个API呢
应该用OCMock的哪个API呢?OCMStrictClassMock(cls)? OCMClassMock(cls)? OCMPartialMock(obj)?
其实这里按照常规的mock测试一个API都用不上。因为我们mock出来的东西(对象或者是类)只能在我们的测试用例中,updateStatusNumber方法里面调用的永远是DemoStatusManage的原生类。
那如何才能让sharedManage不管在哪里(测试用例中和updateStatusNumber中)都返回我们的mock对象呢,答案是用category重写sharedManage让它返回我们的mock对象.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@interface DemoStatusManage (UnitTest) @end static DemoStatusManage *mock = nil; @implementation DemoStatusManage (UnitTest) + (instancetype)sharedManage { if (mock) return mock; static dispatch_once_t once; static DemoStatusManage *manage; dispatch_once(&once, ^{ manage = [[DemoStatusManage alloc] init]; }); return manage; } @end |
这样在我们的单元测试类中只要在测试case中初始化一下mock,sharedManage不管在哪里调用就都会返回我们需要的mock对象了。
1 |
的实例方法,那么这个Signletion的类初始化方法(eg:sharedMange())必须返回一个mock对象。因为只有mock对象才可以做stub操作。那么我们应该如何mock我们的Singletion呢,我们通过下面的例子一步步分析解决这个问题。
Singleton场景比如我有一个Singleton的类(DemoStatusManage),他有一个实例方法currentStatus会返回一个1-100的随机数。
然后在我的另外一个类中会去调用这个Singletion的currentStatus方法,并且将返回的数据渲染到另外那个类的label文案上。
这是一个很简单的Singletion场景,但是在测试 应该用OCMock的哪个API呢应该用OCMock的哪个API呢?OCMStrictClassMock(cls)? OCMClassMock(cls)? OCMPartialMock(obj)? 其实这里按照常规的mock测试一个API都用不上。因为我们mock出来的东西(对象或者是类)只能在我们的测试用例中,updateStatusNumber方法里面调用的永远是DemoStatusManage的原生类。 那如何才能让sharedManage不管在哪里(测试用例中和updateStatusNumber中)都返回我们的mock对象呢,答案是用category重写sharedManage让它返回我们的mock对象.
这样在我们的单元测试类中只要在测试case中初始化一下mock,sharedManage不管在哪里调用就都会返回我们需要的mock对象了。
|