美文网首页iOS学习笔记iOS程序猿
iOS UnitTest 学习 (二) 了解单元测试的机制,以

iOS UnitTest 学习 (二) 了解单元测试的机制,以

作者: DingGa | 来源:发表于2021-07-07 21:50 被阅读0次

    前言

    除了断言,还有更多的测试。XCTest 什么时候创建和运行测试?iOS程序员特别容易对测试生命周期做出错误的假设。这些假设会导致测试设计中的错误。

    比如我们经常遇到的,一个测试用例,在单独运行的情况下可以测试通过,但是在项目组合测试中失败,为了避免不稳定的测试,我们需要给测试一个稳定,干净的环境.

    测试方法中的代码组织成三个部分来明确这些阶段:

    • 安排、Arrange 安排,它是定义所有变量和模型的部分。
    • 行动、Action 行为:是触发被测方法并返回结果的部分。
    • 断言` Assert 断言:这是评估预期结果的部分。

    记住AAA 是单元测试的重要部分

    XCTest的使用

       func test_methodOne() {
            let sut = MyClass()
    
            sut.methodOne()
    
            // Normally, assert something
        }
    

    名称sut代表被测系统,通常缩写为SUT。这是“我们正在测试的东西”的常用术语。与这个简单的例子不同,测试通常有很多对象在起作用。使用像sut这样一致的名称可以清楚地表明测试将作用于哪个对象。它还可以更轻松地重用测试代码片段。

    XCTest 测试机制

    • XCTest 在测试时候,搜索从XCTestCase继承的所有类。
    • 对于这样的类,它会找到每个测试方法。这些方法的名称以test开头,没有参数,也没有返回值。如func test_methodOne()
    • 对于每个这样的测试方法,它都会创建一个类的实例。使用 Objective-C runtime,它会记住该实例将运行哪个测试方法。
    • XCTest 将子类的实例收集到测试套件中。
    • 当它完成所有测试用例的创建后,XCTest 才会开始运行它们。
    class MyClassTests: XCTestCase {
        private let sut = MyClass()
    
        func test_methodOne() {
            sut.methodOne()
    
            // Normally, assert something
        }
    
        func test_methodTwo() {
            sut.methodTwo()
    
            // Normally, assert something
        }
    }
    
    举例

    MyClassTests 有两个测试方法 test_methodOnetest_methodTwo
    那么,在XCTest运行时, 会找到MyClassTests。它搜索以test开头的方法名称,并找到两个。所以它创建了MyClassTests 的两个实例:一个实例运行test_methodOne,另一个运行test_methodTwo

    使用setUp(),tearDown()优化

    XCTestCase定义了两个方法,setUp和tearDown,这两个方法设计为在子类中被覆盖。

    XCTest 中的测试运行程序保证每个测试用例的顺序如下:

    • 呼叫的setUp(创建对象)。
    • 调用测试方法。
    • 调用tearDown(销毁)。
    class MyClassTests: XCTestCase {
        private var sut: MyClass!
    
        override func setUp() {
            super.setUp()
            sut = MyClass()
        }
    
        override func tearDown() {
            sut = nil
            super.tearDown()
        }
    
        func test_methodOne() {
            sut.methodOne()
    
            // Normally, assert something
        }
    
        func test_methodTwo() {
            sut.methodTwo()
    
            // Normally, assert something
        }
    }
    

    注意: 初始化存储属性的测试类中。要将这些属性从let更改为var。并且添加

    Tips 检测测试Log

    通过如图所示,我们可以快速找到test的失败消息


    截屏2021-07-07 下午8.03.37.png

    如何写好项目里的测试?

    代码测试覆盖率

    在 Xcode 菜单中,选择ProductSchemeEdit Scheme...或按 - <

    截屏2021-07-07 下午9.13.20.png

    现在我们就设置好了测试覆盖率

    + U 试一下

    截屏2021-07-07 下午9.21.27.png

    并且 Xcode 菜单中选择Editor ▶ Code Coverage。

    截屏2021-07-07 下午9.23.06.png

    红色区域的数字代表我们这段代码测试了几次,在红色条纹区域。将鼠标光标悬停在该区域,您会看到情况发生了变化,如下所示:

    截屏2021-07-07 下午9.24.42.png

    绿色部分显示了我们接触过的代码。带有else 的那一行部分是绿色的,部分是红色的。这为我们提供了一种查看行内代码覆盖率的方法。

    为现有代码添加测试

    举例

    class CoveredClass {
    
        static func max(_ x: Int, _ y: Int) -> Int {
            if x < y {
                return y
            } else {
                return x
            }
        }
    }
    

    如果代码正在使用中,我们就不需要从需求逆向工作。相反,我们可以编写有效地使用遗留代码称为特性测试的内容。这些是捕获代码实际行为的测试。

    要编写特性测试,请执行以下操作:

    • 从测试中调用代码,产生某种结果。
    • 编写一个断言,将结果与您知道不匹配的值进行比较。
    • 运行测试。失败消息将告诉您实际结果。
    • 调整断言,使其预期实际结果。
    • 重新运行测试以查看它是否通过。

    1,2部分

        func test_max_with1And2_shouldReturnSomething() {
            let result = CoveredClass.max(1, 2)
    
            XCTAssertEqual(result, -123)
        }
    
    截屏2021-07-07 下午9.33.33.png

    3.运行测试。这给了我们一条失败消息

    4.我们从失败消息中复制实际值2并粘贴到断言中

        func test_max_with1And2_shouldReturn2() {
            let result = CoveredClass.max(1, 2)
    
            XCTAssertEqual(result, 2)
        }
    

    5.运行

    截屏2021-07-07 下午9.37.40.png

    我们本次的测试就完成了!!! 通过~

    当然,如果你想要更好的测试覆盖率,让我们添加一个测试来覆盖后半部分。
    条件是if x < y

        func test_max_with3And2_shouldReturn3() {
            let result = CoveredClass.max(3, 2)
    
            XCTAssertEqual(result, 3)
        }
    

    这应该给我们 100% 的覆盖率。但是实际上,会由于有个},很难做到100%覆盖率

    截屏2021-07-07 下午9.45.53.png

    多写几个,也是可以完成100% 覆盖率的,但是,我们不应该成为测试覆盖率的奴隶.

    Tips

    一个好的测试名称包含三个部分:

    • 测试的内容是什么。这通常是一个函数名。
    • 测试条件。有什么不同的输入?
    • 预期的结果。

    相关文章

      网友评论

        本文标题:iOS UnitTest 学习 (二) 了解单元测试的机制,以

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