【实战】入门级XCTest单元测试

到现在,还没有写过单元测试方面的文章,这对于整个开发流程来说,是不完善的。这次写一些关于单元测试方面的文章,以完善这方面的内容。

iOS的单元测试分为接口测试和界面测试,今天这篇文章讲接口测试。这里所说的接口是指要测试模块的函数,并非模块对外开放的“接口”之意。

本文分四个部分
加减乘除的单元测试
插入和冒泡排序的单元测试
插入和冒泡排序的性能测试
网络API的单元测试

一、加减乘除的单元测试
下面是详细过程:先新建一个基于NSObject的类(Maths),
具体操作为File->New->File…->Cocoa Touch Class,如下图所示:

这个类就是我们平时写的功能代码,即待要测试的代码。在这份代码中实现了四个方法,add,sub,mul和div。如下:
class Maths: NSObject {
func add(_ a: Int, _ b:Int) -> Int {
return a + b
}

func sub(_ a: Int, _ b:Int) -> Int {
   return a - b
}

func mul(_ a: Int, _ b:Int) -> Int {
    return a * b
}

func div(_ a: Int, _ b:Int) -> Int {
    return a / b
}

}
接下来,我们针对这四个函数进行单元测试。
先新建一个测试文件,右键->New Files…, 在弹出的界面中选择Unit Test Case Class。注意这里选择的是Unit Test,而不是UI Test Case。如下图

至此,创建好测试文件。
在此文件上,我们要做好四个必要步骤:
1.导入工程。导入工程是让工程内所有文件都包含到测试模块,方便调用待测试类或类方法。
2.声明测试类对象。对测试类进行声明。
3.创建测试类对象。创建和初始化对象,在后面的测试中直接调用对象的方法。
4.在释放处,释放测试类对象。在该释放的地方,释放对象,完成资源的回收。
具体如下图:

然后对add、sub、mul和div四个方法的测试,也就很简单。具体如下:
func testAdd() throws {
let a = Int.random(in: 1…100)
let b = Int.random(in: 1…100)

    XCTAssertEqual(a + b, maths.add(a, b))
}

func testSub() throws {

    let a = Int.random(in: 1...100)
    let b = Int.random(in: 1...100)

    XCTAssertEqual(a - b, maths.sub(a, b))
}

func testMul() throws {

    let a = Int.random(in: 1...100)
    let b = Int.random(in: 1...100)

    XCTAssertEqual(a * b, maths.mul(a, b))
}

func testDiv() throws {

    let a = Int.random(in: 1...100)
    let b = Int.random(in: 1...100)

    XCTAssertEqual(a / b, maths.div(a, b))
 }

简单来说,就是生成两个随机数字a、b,使用XCTAssert类的宏,判断预期值与实际的数值是否一致?一致就测试通过,否则就测试失败。

点击每个测试方法前面的菱形图标,执行代码。结果是测试通过的。

当然,对于上面的形式,还有一种情况,没有类(直接是全局函数),那就不需要2、3、4步骤了。

这里要注意的是,对于全局函数,就没有声明和创建对象的必要,当然也没有释放对象,只有直接的调用方法。
介绍完数学的加减乘除的方法的测试,下面在再介绍下排序算法的测试。

二、插入和冒泡排序的单元测试
这里就以插入排序和冒泡排序算法为例。
先还是在工程中新建待测试文件(Sorter.swift),并实现插入排序和冒泡排序算法。如下代码
class Sorter: NSObject {
//交换数据
func swap(arr:inout [Int],index:Int,index2:Int) {
let tmp = arr[index]
arr[index] = ar[index2]
arr[index2] = tmp
}

//插入排序
func insertSort(arr:inout [Int]) {
    for i in 1 ..< arr.count {
        for j in stride(from: i - 1, to:  -1, by: -1) {

            if arr[j + 1] < arr[j] {
                swap(arr: &arr, index: j, index2: j + 1)
            } else {
                break
            }
        }
    }
}

//冒泡排序
func bubbSorter(_ arr:inout [Int]) {

    for i in 0 ..< arr.count - 1 {
        for j in stride(from: 0, to arr.count - i - 1, by: 1) {

            if arr[j + 1] > arr[j] {
                swap(arr: &arr, index: j + 1, index2: j)
            }
        }
    }
}

}
这个文件中实现了三个函数,分别是交换函数(swap)、插入排序和冒泡排序。然后对其进行单元测试。同样地,还是新建一个测试文件。

对于插入排序算法,没有理解其算法,就很容易写出错误的。这里需要记住一点的是:针对前面 i个数据进行排序。即i,i-1,i-2…. i,0进行遍历并比较。
换做C/C++的写法,
stride(from: i – 1, to: -1, by: -1) 等价于 for(int j = i; j>0; j–)。
完整的C/C++的写法:
for (int i = 0; i< arr.count – 1; i++) { for(int j = i; j>0; j–) {
if arr[j + 1] < arr [j] { swap(arr: &arr, index: j + 1, index2: j) } } } 同理于冒泡算法的完整算法 for i in 0 ..< arr.count – 1 { for j in 0 ..< arr.count – i – 1 { if arr[j + 1] > arr[j] {
swap(arr: &arr, index: j + 1, index2: j)
}
}
}
以上就是C/C++的补充实现。

下面再说单元测试。
同样地,对于类的测试,还是要做前面所的四步。

完成了初始化后,就针对insertSort和bubbSorter函数进行测试,测试代码如下:
func testInsertSort() throws {
var arr = [Int]()
for _ in 0 ..< 20 {
let a = Int.random(in: 1…20)
arr.append(a)
}
sorter.insertSort(arr: &arr)
XCTAssertTrue(isSorter(arr: &arr))
}

func testBubbSort() throws {
    var arr = [Int]()
    for _ in 0 ..< 20 {
        let a = Int.random(in: 1...20)
        arr.append(a)
    }
    sorter.bubbSorter(&arr)
    XCTAssertTrue(isSorter(arr: &arr))
}

在这里,首先会生成一个随机数组arr,然后传入待测试代码,进行排序,把排序后的结果与预期值进行比较。

与之前的代码有一点区别:就是对于预期值,使用了一个函数(isSorter)进行判断,其判断的依据数组内的元素是否按一定次序排列。体如下:
func isSorter(arr:inout [Int]) -> Bool {

for i in 0 ..< arr.count {
    if arr[i + 1] < arr[i] {
        return false
    }
}
return true

}
然后点击方法前的菱形图标,执行对该函数的测试,执行结果是测试通过的。
下面在说一下,XCTest的性能测试。

三、插入和冒泡排序的性能测试
XCTest的性能测试比较简单,直接在self.measure中添加代码即可,系统会采样执行10次self.measure内的代码,最终得到被测试代码的性能情况。

在这里直接对上面的两个排序算法进行性能测试,直接上代码。
func testInsertSortPerformance() throws {
// This is an example of a performance test case.
var arr = [Int]()
for _ in 0 ..< 20
let a = Int.random(in: 1…20)
arr.append(a)
}
self.measure {
// Put the code you want to measure the time of here.
sorter.insertSort(arr: &arr)
}
}

func testBubbSortPerformance() throws {
    // This is an example of a performance test case.
    var arr = [Int]()
    for _ in 0 ..< 20 {
        let a = Int.random(in: 1...20)
       arr.append(a)
    }
    self.measure {
        // Put the code you wat to measure the time of here.
        sorter.bubbSorter(&arr)
    }
}

这样就得到插入排序和冒泡排序的性能测试。

介绍完性能测试,下面再讲下网络API接口的单元测试。

四、网络API的单元测试
对于网络API接口的测试,也类似前面的排序测试一样,需要对测试对象的生命周期管理(声明、创建/初始化、销毁释放)。
所以先完成对象的四个步骤。

创建完测试对象后,就开始写测试函数。这里直接上代码。
func testURL() throws {
let url = URL(string: “https://www.baidu.com”)
let promise = expectation(description: “Status code:200”)

    let task = session.dataTask(with: url!) { data,responds,error in
        if let error = error {
            XCTFail("Error:\(error.localizedDescription)")
        } else {
            let res = responds as? HTTPURLResponse

            let status = res?.statusCode
            if status == 200 {
               promise.fulfill()
            }
        }
   }
    task.resume()
    wait(for: [promise], timeout: 5)
}

关于网络测试有三个注意的点:
1.使用expectation类型的promise。
2.在达到预期期望时,需要使用fulfill表示完成预期期望
3.最后要通过wait来设置预期期望的超时时间。每一个网络请求都要设置超时时间,以处理超时的异常情况。如下图所示

以上就是入门级实战XCTest的单元测试。包括了数学的基础函数、排序算法和网络请求三方面的测试,其中还有包括了排序算法的性能测试。

以上案例是从网络教程中学习并参考,并在本机实践通过,有兴趣的可以验证。

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/418871.html

(0)
联系我们
联系我们
分享本页
返回顶部