ios 自动化测试的简单运用

作者: 西风那个吹呀吹 | 来源:发表于2017-05-25 17:00 被阅读181次

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

    测试框架

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

    1.png 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是否正确了:

    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;
    }
    

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

    5.png

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

    #import <XCTest/XCTest.h>
    #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:

    9.png

    本文Demo

    相关文章

      网友评论

        本文标题:ios 自动化测试的简单运用

        本文链接:https://www.haomeiwen.com/subject/kwfixxtx.html