单元测试的本质是给定条件 测试 判断是否达到预期
单元测试的优势
- 辅助开发
- 能给节省时间
- 简化测试
- 架构代码(使之更加规范 便于单元测试)
单元测试
所有的测试方法都要以test开头 否则不能执行
- 逻辑测试
// 逻辑测试
- (void)testExample {
// 10 + 20 = 30 = 20 ?
// 测试三部曲
// give -- 我们给预期
int num1 = 10;
int num2 = 20;
// when
int num3 = [self.vc getPlus:num1 num2:num2];
// then
XCTAssertEqual(num3, 30,@"算法不对");
}
- 异步测试
异步测试 是对异步回调进行监听
// 异步测试 - test开头
- (void)tesAsy{
//give 期望
XCTestExpectation *ec = [self expectationWithDescription:@"执行时间过长"];
//when
[self.vc loadData:^(id data) {
//give //when 逻辑测试
XCTAssertNil(data);
//执行到位 会给出相应的提示 监控作用
[ec fulfill];
}];
//then
[self waitForExpectationsWithTimeout:2 handler:^(NSError * _Nullable error) {
NSLog(@"error == %@",error);
}];
}
- 性能测试
性能测试是相对的 跟产品要求的时间进行对比
性能测试是测试性能的花费时间 容错范围 总时间 平均时间
//性能测试
//性能只有相对性
- (void)testPerformanceExample {
// This is an example of a performance test case.
//监控性能比的异步函数
[self measureBlock:^{
//测试性能
//总时间
//平均时间
//散列分布
[self.vc openCamera];
}];
}
- 局部测试
//局部测试
- (void)testPerformance{
[self measureMetrics:@[XCTPerformanceMetric_WallClockTime] automaticallyStartMeasuring:NO forBlock:^{
[self.vc openCamera];//提供条件
//考量测试的点在 startMeasuring 和 stopMeasuring之间 也就是局部测试
[self startMeasuring];
[self.vc openCamera];//局部测试
[self stopMeasuring];
}];
}
- UI测试
- (void)testLogin{
// application - window - dom 树结构
//拿到当前application程序
XCUIApplication *app = [[XCUIApplication alloc] init];
//当前nav下的view--->self.view
XCUIElement *element = [[[[app.otherElements containingType:XCUIElementTypeNavigationBar identifier:@"login"] childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element;
//拿到当前view下的textfeild的搜索器
XCUIElementQuery *tfQuery = [element childrenMatchingType:XCUIElementTypeTextField];
XCUIElement *accountTF = [tfQuery elementBoundByIndex:0];
XCUIElement *passwordTF = [tfQuery elementBoundByIndex:1];
//拿到当前view下的button的搜索器
XCUIElementQuery *btnQuery = [element childrenMatchingType:XCUIElementTypeButton];
XCUIElement *loginBtn = [btnQuery elementBoundByIndex:0];
//UI操作
[accountTF tap];
[accountTF typeText:@"123456"];
[passwordTF tap];
[passwordTF typeText:@"12345"];
[loginBtn tap];
//*********************键盘delete按钮 -- 注意 -- 当前的键盘一定要打开 - 不然就会view 找不到 -- 前往不要犯低级错误*********************
XCUIElement *delete = app.keys[@"delete"];
[delete doubleTap];
[loginBtn tap];
//快速获取按钮
[app.navigationBars[@"loginSuccessView"].buttons[@"login"] tap];
}
- OCMock
用于模拟依赖注入 和 测试(单一变量原则)
作用
1.创建一个普通对象 来添加虚拟参数 + 返回值
2.验证结果
3.创建一个虚拟对象
- (void)testPerson{
Person *p = [[Person alloc] init];
// cls ---> runtime
Person *mock_p = OCMClassMock([Person class]);
OCMStub([mock_p getPersonName]).andReturn(@"OCMock");
XCTAssertEqualObjects([mock_p getPersonName], [p getPersonName],@"===");
}
- (void)testTableViewDelete{
ViewController *vc = OCMClassMock([ViewController class]);
// UITableView *ocTableView = OCMClassMock([UITableView class]);
NSIndexPath *path = [NSIndexPath indexPathForRow:12 inSection:0];
[vc tableView:vc.tableView commitEditingStyle:UITableViewCellEditingStyleDelete forRowAtIndexPath:path];
OCMVerify([vc.tableView deleteRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationFade]);
}
- (void)testMockDemo{
OCMockViewController *vc = [[OCMockViewController alloc] init];
// manager
id manager = OCMClassMock([Manager class]);
// 数据
Dog *dog1 = [[Dog alloc] init];
dog1.userName = @"123";
Dog *dog2 = [[Dog alloc] init];
dog2.userName = @"456";
NSArray *array = @[dog1,dog2];
OCMStub([manager fetchDogs]).andReturn(array);
// 视图
id cardView = OCMClassMock([IDCardView class]);
vc.idCardView = cardView;
OCMVerify([vc updateIDCardView]);
}
OCMock用例结束之后要stopMocking 避免由于单例或者property导致的用例之间相互影响
网友评论