1,mock单例:
单例类OKDataManager 有模型属性userModel 通过mock单例设置固定的userModel属性userId
id mockManager = OCMClassMock([OKDataManager class]);
//返回的是自身
OCMStub([mockManager shareManager]).andReturn(mockManager);
OKUserInfoModel *userModel = [[OKUserInfoModel alloc] init];
userModel.userId = @"123456"; //在测试调用的地方userId返回的就是123456
OKDataManager *manager = [OKDataManager shareManager];
OCMStub([manager userInfoModel]).andReturn(userModel);
2,reject 表示不执行某个方法
工程中要测试的方法:
- (void)searchByMsg:(NSString *)msg {
if (!msg.length) {
return;
}
[self requestSearchByMsg:msg];
}
测试类中:
- (void)setUp {
[super setUp];
_vc = [[SearchVC alloc] init];
_mockVC = OCMPartialMock(_vc);
}
//调用测试方法,因为搜索的内容为nil,所以断言没有调用- (void)requestSearchByMsg:方法
- (void)testSearchWithoutMsg {
[_mockVC searchByMsg:nil];
OCMExpect([[_mockVC reject] requestSearchByMsg:[OCMArg any]];
}
3,测试控制器跳转方法
//需要测试的工程代码
- (void)pushWithOrderId:(NSString *)orderId {
DetailVC *detailVC = [[DetailVC alloc] init];
detailVC.ID = orderId;
[self.navigationController pushViewController:detailVC animated:YES];
}
//测试代码
- (void)testPushWithOrderId {
//当前控制器
ViewController *vc = [[ViewController alloc] init];
id mockVC = OCMPartialMock(vc);
//mock一个导航控制器
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:mockVC];
//调用要测试的方法
[mockVC pushToServiceOrderWithOrderId:@"0123"];
//验证是否调用了push方法
OCMVerify([[mockVC navigationController] pushViewController:[OCMArg any] animated:YES]);
//但是不能验证跳转后的控制器类型,目前只做到方法是否调用
// XCTAssertTrue([navigationController.topViewController isKindOfClass:[DetailVC class]]);
}
4,需要测试的工程类的私有变量和方法可以通过在测试工程类中添加工程类的分类方法和属性变量来实现,在测试工程中,调用工程类的私有变量和方法.设置属性时,也可以通过setValue: forKey:来设置私有变量.
//工程中VCClass要测试的方法
@interface OKDataHotVC ()
@property (nonatomic, strong) TypeView *typeView; //私有变量
@property (nonatomic, strong) NSArray *types; //私有变量
@end
@implementation VCClass
//要测试的方法 ,typeView, types为控制器私有变量
- (void)showTypeView:(id)sender {
if (self.typeView.isShowed) {
[self.typeView hideWithAnimation:YES];
}
else {
[self.typeView showInSuperView:self.view animation:YES];
}
}
@end
//测试工程中
@interface VCClass (Test)
//添加VCClass类的私有变量,通过分类实现types的测试工程引用
@property (nonatomic, strong) NSArray *types;
//添加AClass类的私有方法
- (void)showTypeView:(id)sender;
@end
@interface AClassTest : XCTestCase
@end
@implementation AClassTest
- (void)setUp {
[super setUp];
}
- (void)tearDown {
[super tearDown];
}
//通过setValue: forKey:来设置私有变量typeView
- (void)testShowTypeViewForHide {
VCClass *vc = [[VCClass alloc] init];
id typeViewMock = OCMClassMock([TypeView class]);
//给vc的私有变量typeView赋值
[vc setValue: typeViewMock forKey:@"typeView"];
//设置为已经显示,调用隐藏的方法
OCMStub([typeViewMock isShowed]).andReturn(YES);
[vc showTypeView:nil];
OCMVerify([typeViewMock hideWithAnimation:YES]);
}
@end
5,测试添加通知的方法
工程中要测试的方法:
- (void)methodWithPostNotification {
//balalaba 执行代码.....
[[NSNotificationCenter defaultCenter] postNotificationName:@"name" object:nil];
}
测试方法中:
- (void)testPostNotification {
ViewController *vc = [[ViewController alloc] init];
id observerMock = OCMObserverMock();
//给通知中心设置观察者
[[NSNotificationCenter defaultCenter] addMockObserver: observerMock name:@"name" object:nil];
//设置观察期望
[[observerMock expect] notificationWithName:@"name" object:[OCMArg any]];
//调用要验证的方法
[vc methodWithPostNotification];
// 调用验证
OCMVerifyAll(popObserverMock);
}
6,mock Block回调事件
如果请求的回调是通过block实现,可以不用请求后台数据,通过mock模拟回调数据
工程中请求类Request方法:
+ (void) requestDataByModel:(RequestModel*)requestModel completeBlock:(void(^)(BOOL result, NSString *code ,NSString *msg))completeBlock
{
requestModel.requestUrl = HTTP_FOR_Data_URL;
[RequestTools sendRequest:requestModel success:^(id returnValue) {
NSDictionary *dic = [returnValue ok_dictionary];
NSString *msg = [dic objectForKey:@"msg"];
NSString *code = [dic objectForKey:@"code"];
if ([code isEqualToString:@"0"]) {
if (completeBlock) {
completeBlock(YES, code, msg);
}
}
else{
if (completeBlock) {
completeBlock(NO, code, msg);
}
}
} failure:^(NSError *error) {
if (completeBlock) {
completeBlock(NO, @"1000", @"");
}
}];
}
工程中控制器ViewController中调用请求的方法(即需要测试的方法):
- (void)requestDataById:(NSString *)Id {
if(Id.length == 0){
return;
}
RequestModel *model = [[RequestModel alloc] init];
[Request requestDataByModel: model completeBlock:^(BOOL result, NSString *code ,NSString *msg ){
if(result){
NSLog(@"do something for correct situation:%@",msg);
[self doSomethingCorrectly];
}
else {
NSLog(@"do something for error situation:%@",msg);
[self doSomethingWrong];
}
}];
}
测试工程中:
//测试方法
- (void)testRequestDataById {
ViewController *vc = [[ViewController alloc] init];
//部分mock,需要验证vc是否调用方法
id mockVC = OCMPartialMock(vc);
//mock请求类
id mockRequest = OCMClassMock([Request class]);
//mock block数据
OCMStub([mockRequest requestDataByModel:[OCMArg any] completeBlock:[OCMArg any]]).andDo(^(NSInvocation *invocation){
void (^resultResponse)(BOOL result, NSString *code, NSString *msg);
//第0个和第1个参数是self,SEL,第2个是model,第3才是block
[invocation getArgument:&resultResponse atIndex:3];
//4. 设置返回数据
resultResponse(YES,@"0",@"成功");
});
//调用要验证的方法,没有id时,通过reject验证不调用请求方法
[mockVC requestDataById:nil];
OCMVerify([[mockRequest reject] requestDataByModel:[OCMArg any] completeBlock:[OCMArg any]]);
//调用要验证的方法,有id
[mockVC requestDataById:@"123"];
//验证是否调用相应的方法
OCMVerify([mockVC doSomethingCorrectly]);
}