zoukankan      html  css  js  c++  java
  • iOS 单元测试之XCTest详解(一)

     

    iOS 单元测试之XCTest详解(一)

    http://blog.csdn.net/hello_hwc/article/details/46671053

    原创blog,转载请注明出处 
    blog.csdn.net/hello_hwc 
    欢迎关注我的iOS-SDK详解专栏 
    http://blog.csdn.net/column/details/huangwenchen-ios-sdk.html


    前言:测试是一个好的App不可缺少的部分。每一个App都是由一个个小的功能组合到一起的。而这些小的功能又是由一个个函数或者说算法组合到一起的。单元测试就是对这些小的功能或者函数进行测试,良好的单元测试会让代码的健壮性提高很多。XCTest就是XCode为我们提供的一个框架,它提供了各个层次的测试。


    XCTestCase

    每个XCode创建iOS的工程中都有一个叫做”工程名Tests”的分组,这个分组里就是XCTestCase的子类,XCTest中的测试类都是继承自XCTestCase。 
    例如新建一个工程,命名为Demo,就能看到如图 
     
    看一下这个自动创建的文件里都包含了哪些内容

    #import <UIKit/UIKit.h>
    #import <XCTest/XCTest.h>
    
    @interface DemoTests : XCTestCase
    
    @end
    
    @implementation DemoTests
    
    - (void)setUp {
        [super setUp];
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }
    
    - (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.
        XCTAssert(YES, @"Pass");
    }
    
    - (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
    
    • 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

    测试用例的命名

    XCTest中所有的测试用例的命名都是以test开头的。例如上文中的

    - (void)testExample {
        // This is an example of a functional test case.
        XCTAssert(YES, @"Pass");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    setUp和tearDown

    Setup是在所有测试用例运行之前运行的函数,在这个测试用例里进行一些通用的初始化工作

    tearDown是在所有的测试用例都执行完毕后执行的


    XCode的测试用例导航

    测试用例的导航如图,在测试用例的导航里,我们可以运行一组测试用例,也可以运行一个单独的测试用例 

    可以鼠标右键来新建一组测试用例。 

    也可以为测试用例添加失败断点来方便我们调试 


    普通方法测试

    例如,新建一个类命名为Model,他有这个方法用来生成10以内的随机数。

    -(NSInteger)randomLessThanTen{
        return arc4random()%10;
    }
    • 1
    • 2
    • 3

    于是,测试方法为

    -(void)testModelFunc_randomLessThanTen{
        Model * model = [[Model alloc] init];
        NSInteger num = [model randomLessThanTen];
        XCTAssert(num<10,@"num should less than 10");
    }
    • 1
    • 2
    • 3
    • 4
    • 5

    我们点击如图的左边图标单独运行这个测试用例,当然也可以在上文我提到的导航栏里单独运行。 
    这里写图片描述 
    然后会看到输出表示这个测试用例通过

    Test Suite 'Selected tests' started at 2015-06-28 05:24:56 +0000
    Test Suite 'DemoTests.xctest' started at 2015-06-28 05:24:56 +0000
    Test Suite 'DemoTests' started at 2015-06-28 05:24:56 +0000
    Test Case '-[DemoTests testModelFunc_randomLessThanTen]' started.
    Test Case '-[DemoTests testModelFunc_randomLessThanTen]' passed (0.000 seconds).
    Test Suite 'DemoTests' passed at 2015-06-28 05:24:56 +0000.
         Executed 1 test, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
    Test Suite 'DemoTests.xctest' passed at 2015-06-28 05:24:56 +0000.
         Executed 1 test, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
    Test Suite 'Selected tests' passed at 2015-06-28 05:24:56 +0000.
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    常用断言

    如何判断一个测试用例成功或者失败呢?XCTest使用断言来实现。 
    最基本的断言 
    表示如果expression满足,则测试通过,否则对应format的错误。

    XCTAssert(expression, format...)
    • 1

    还有一个用来直接Fail的断言

    XCTFail(format...)
    • 1

    其他一些常用的断言:

    XCTAssertTrue(expression, format...)
    XCTAssertFalse(expression, format...)
    XCTAssertEqual(expression1, expression2, format...)
    XCTAssertNotEqual(expression1, expression2, format...)
    XCTAssertEqualWithAccuracy(expression1, expression2, accuracy, format...)
    XCTAssertNotEqualWithAccuracy(expression1, expression2, accuracy, format...)
    XCTAssertNil(expression, format...)
    XCTAssertNotNil(expression, format...)
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    性能测试

    所谓性能测试,主要就是评估一段代码的运行时间,XCTest的性能的测试利用如下格式

    - (void)testPerformanceExample {
        // This is an example of a performance test case.
        [self measureBlock:^{
            // Put the code you want to measure the time of here.
        }];
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    例如,我要评估一段代码,这段代码的功能是把一张图片缩小到指定的大小。 
    这段代码如下,这段代码我放在UIImage的类别里。

    + (UIImage*)imageWithImage:(UIImage*)image
                  scaledToSize:(CGSize)newSize
    {
        UIGraphicsBeginImageContext( newSize );
        [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
        UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return newImage;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    然后测试用例如图,主要判断resize后是否为nil,并且尺寸是否对。

    - (void)testPerformanceExample {
        UIImage * image = [UIImage imageNamed:@"icon.png"];
        [self measureBlock:^{
            UIImage * resizedImage = [UIImage imageWithImage:image scaledToSize:CGSizeMake(100, 100)];
            XCTAssertNotNil(resizedImage,@"resized image should not be nil");
            CGFloat resizedWidth = resizedImage.size.width;
            CGFloat resizedHeight = resizedImage.size.height;
            XCTAssert(resizedHeight == 100 && resizedWidth == 100,@"Size is not right");
        }];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    输出

    Test Suite 'Selected tests' started at 2015-06-28 05:42:39 +0000
    Test Suite 'DemoTests.xctest' started at 2015-06-28 05:42:39 +0000
    Test Suite 'DemoTests' started at 2015-06-28 05:42:39 +0000
    Test Case '-[DemoTests testPerformanceExample]' started.
    /Users/huangwenchen/Desktop/Demo/DemoTests/DemoTests.m:41: Test Case '-[DemoTests testPerformanceExample]' measured [Time, seconds] average: 0.000, relative standard deviation: 40.714%, values: [0.000241, 0.000116, 0.000128, 0.000089, 0.000087, 0.000081, 0.000101, 0.000093, 0.000092, 0.000087], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
    Test Case '-[DemoTests testPerformanceExample]' passed (0.357 seconds).
    Test Suite 'DemoTests' passed at 2015-06-28 05:42:40 +0000.
         Executed 1 test, with 0 failures (0 unexpected) in 0.357 (0.358) seconds
    Test Suite 'DemoTests.xctest' passed at 2015-06-28 05:42:40 +0000.
         Executed 1 test, with 0 failures (0 unexpected) in 0.357 (0.358) seconds
    Test Suite 'Selected tests' passed at 2015-06-28 05:42:40 +0000.
         Executed 1 test, with 0 failures (0 unexpected) in 0.357 (0.360) seconds
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    异步测试

    异步测试的逻辑如下,首先定义一个或者多个XCTestExpectation,表示异步测试想要的结果。然后设置timeout,表示异步测试最多可以执行的时间。最后,在异步的代码完成的最后,调用fullfill来通知异步测试满足条件。

    - (void)testAsyncFunction{
        XCTestExpectation * expectation = [self expectationWithDescription:@"Just a demo expectation,should pass"];
        //Async function when finished call [expectation fullfill]
        [self waitForExpectationsWithTimeout:10 handler:^(NSError *error) {
            //Do something when time out
        }];
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    举例

    - (void)testAsyncFunction{
        XCTestExpectation * expectation = [self expectationWithDescription:@"Just a demo expectation,should pass"];
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            sleep(1);
            NSLog(@"Async test");
            XCTAssert(YES,"should pass");
            [expectation fulfill];
        });
        [self waitForExpectationsWithTimeout:10 handler:^(NSError *error) {
            //Do something when time out
        }];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    测试结果

    Test Suite 'Selected tests' started at 2015-06-28 05:49:43 +0000
    Test Suite 'DemoTests.xctest' started at 2015-06-28 05:49:43 +0000
    Test Suite 'DemoTests' started at 2015-06-28 05:49:43 +0000
    Test Case '-[DemoTests testAsyncFunction]' started.
    2015-06-28 13:49:44.920 Demo[2157:145428] Async test
    Test Case '-[DemoTests testAsyncFunction]' passed (1.006 seconds).
    Test Suite 'DemoTests' passed at 2015-06-28 05:49:44 +0000.
         Executed 1 test, with 0 failures (0 unexpected) in 1.006 (1.007) seconds
    Test Suite 'DemoTests.xctest' passed at 2015-06-28 05:49:44 +0000.
         Executed 1 test, with 0 failures (0 unexpected) in 1.006 (1.009) seconds
    Test Suite 'Selected tests' passed at 2015-06-28 05:49:44 +0000.
  • 相关阅读:
    数学+高精度 ZOJ 2313 Chinese Girls' Amusement
    最短路(Bellman_Ford) POJ 1860 Currency Exchange
    贪心 Gym 100502E Opening Ceremony
    概率 Gym 100502D Dice Game
    判断 Gym 100502K Train Passengers
    BFS POJ 3278 Catch That Cow
    DFS POJ 2362 Square
    DFS ZOJ 1002/HDOJ 1045 Fire Net
    组合数学(全排列)+DFS CSU 1563 Lexicography
    stack UVA 442 Matrix Chain Multiplication
  • 原文地址:https://www.cnblogs.com/apem/p/5272537.html
Copyright © 2011-2022 走看看