ios 自动化测试的简单运用

自动化测试就是编写测试代码,代替人工去完成业务与模块的测试。目前人工在测试中还是占比很重的,毕竟代码无法验证非逻辑问题,比如UI控件的显示问题等。

测试框架

XCTest 是Apple 官方提供的测试工具框架。Xcode4.x 时代集成了OCUnit,Xcode5.x 时代升级为 XCTest,Xcode7时代增加了UITest工具。当新建一个项目时,勾选了 Unit Tests 和 UI Tests 选项,我们可以到工程里看到多了两个目录:项目名+Tests项目名+UITests

ios 自动化测试的简单运用_第1张图片
1.png

ios 自动化测试的简单运用_第2张图片
2.png

如果没有上述说的两个文件,可以添加相应的 target。操作路径为: File —> New —> Target —> Test,缺哪个选哪个了,都缺都选。
项目名+Tests.m文件里有四个方法,这个文件主要做一些逻辑的测试。 项目名+UITests.m文件里有三个方法,这个文件主要做一些UI的测试。
XCTest 中的测试类都是继承自 XCTestCase,测试用例方法名自定义以test开头。

单元测试

单元测试最显著最简单的用途就是测试某些小功能等,例如,我们写了一个验证一串字符串是否是手机号格式的方法,我们又不能运行整个工程去验证此方法的正误,因为这样太耗时间了,所以我们用到了单元测试,只需要运行一个测试用例即可。
首先我们新建一个NSString的分类NSString+String文件,在.m文件里实现方法:

//验证手机号
-(BOOL)isPhone{
    if (self.length != 11) {
        return NO;
    }
    
    NSString *shuzi = @"^(11[0-9])";
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"self matches %@",shuzi];
    BOOL flag = [pred evaluateWithObject:self];
    return flag;
}

这样我们可以在单元测试文件XXXTests.m里的编写测试用例了。
首先引入分类的头文件
#import "NSString+String.h"
接着在方法testExample里可以验证isPhone是否正确了:

ios 自动化测试的简单运用_第3张图片
3.png

如图,可以点击目录右侧的三角形或者测试方法左侧的菱形,都可以单独运行此测试用例来验证你所写的 isPhone 方法

当然了,也可以再写个测试用例

- (void)testIsPhone{
    NSString *phone = @"12345678901";
    BOOL flag = [phone isPhone];
    XCTAssertTrue(flag,@"是手机号");
}

上面的测试用例验证了验证手机号的方法是错误的,所以我们回到 isPhone 方法里看看,判断正则不对,修改如下:

-(BOOL)isPhone{
    if (self.length != 11) {
        return NO;
    }
    
    NSString *shuzi = @"^([1][0-9]{10})";
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"self matches %@",shuzi];
    BOOL flag = [pred evaluateWithObject:self];
    return flag;
}

再次运行测试用例,显示绿色对勾表示测试通过,若是红色叉号表示测试失败。

ios 自动化测试的简单运用_第4张图片
5.png

一般用断言去处理测试结果,不然的话测试运行通过后,不知道最终验证的结果是否是正确的是想要的。
还可以建一个测试类,例如网络接口调试类:

#import 
#import "AFNetworking/AFNetworking.h"
@interface NetworkingTest : XCTestCase
@property (nonatomic, strong) AFHTTPSessionManager *AFHTTPManager;
@end
@implementation NetworkingTest
- (void)setUp {
    [super setUp];
    //初始化    
    _AFHTTPManager = [AFHTTPSessionManager manager];
    _AFHTTPManager.requestSerializer.timeoutInterval = 50;
    _AFHTTPManager.securityPolicy.allowInvalidCertificates = YES;
    _AFHTTPManager.requestSerializer = [AFJSONRequestSerializer serializer];
    [_AFHTTPManager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    _AFHTTPManager.responseSerializer.acceptableContentTypes=[NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", nil];
}
- (void)testRequest{
    [self.AFHTTPManager GET:@"http://www.weather.com.cn/data/sk/101010100.html" parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        NSLog(@"返回数据:%@",responseObject);
        [[NSNotificationCenter defaultCenter]postNotificationName:@"Test" object:nil];
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        NSLog(@"hehehe");
        XCTAssertFalse(0,@"服务器连接失败");
        [[NSNotificationCenter defaultCenter]postNotificationName:@"Test" object:nil];
    }];
    
    //该方法监听一个通知,如果在规定时间内正确收到通知则测试通过。
    [self expectationForNotification:@"Test" object:nil handler:nil];
    //waitForExpectationsWithTimeout是等待时间,超过时间而没等到expectationForNotification方法收到“Test”通知就报错。
    [self waitForExpectationsWithTimeout:3 handler:nil];
}
- (void)tearDown {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
    [super tearDown];
}
- (void)testExample {
    // This is an example of a functional test case.
    // Use XCTAssert and related functions to verify your tests produce the correct results.
}
- (void)testPerformanceExample {
    // This is an example of a performance test case.
    [self measureBlock:^{
        // Put the code you want to measure the time of here.
    }];
}
@end

需要注意的是测试方法主线程执行完就结束,想要查看异步方法返回结果,就要有一些异步测试的特殊方法,这里用到了expectationForNotification:方法。
这个NetworkingTest测试类只是简单说明了一下用法,我们可以建新的测试类来调试不同用途的模块或者功能。具体情况具体应对,一切都是为了清晰化而已。

UI测试

用代码写UI测试代码很麻烦,若非特别情况估计没人费劲去手写,还好Xcode为我们提供了录制功能,这里简单介绍一个登录模块测试例子。

7.gif

8.gif

图7是录制演示,当我们启动录制功能后,点击操作界面,随之形成相应的代码,这样就省去了手动写代码的费劲,之后我们可以点击菱形启动测试方法来测试这段UI操作过程。

UI Testing API

  • XCUIApplication
    当前测试应用Target
  • XCUIElement
    UI测试中任何一个元素都被抽象成一个XCUIElement类型
  • XCUIElementQuery
    定位查询当前UI中XCUIElement的一个类
- (void)testExample {
    XCUIApplication *app = [[XCUIApplication alloc] init];
    XCUIElement *phoneTextField = app.textFields[@"phone"];
    [phoneTextField tap];
    [phoneTextField typeText:@"15312345678"];
    
    XCUIElement *passwordTextField = app.textFields[@"password"];
    [passwordTextField tap];
    [passwordTextField tap];
    [passwordTextField typeText:@"1234"];
    
    XCUIElement *loginButton = app.buttons[@"login"];
    [loginButton tap];
    [app.alerts[@"\u63d0\u793a"].buttons[@"\u597d\u7684"] tap];
    [passwordTextField typeText:@"123"];
    [loginButton tap];
}

我们也可以通过identifier获取当前元素XCUIElement类型,例如:

XCUIElement *phoneTextField = [app.textFields elementMatchingType:XCUIElementTypeTextField identifier:@"phone"];

需要手动设置identifier:

ios 自动化测试的简单运用_第5张图片
9.png

本文Demo

你可能感兴趣的:(ios 自动化测试的简单运用)