在项目中使用单元测试

随着项目增加的功能越来越多,渐渐的有一个问题是我们不能不考虑的,就是每次当我们增加了新功能,或者对某些地方做了优化,改版的时候,会不会影响到其他部分代码的正常运行,该如何才能避免每次进行大量的回归测试?这时候单元测试就很有用了。

介绍

在计算机编程中,单元测试(英语:Unit Testing)又称为模块测试, 是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。

单元测试可以让我们在重构优化代码的时候及时发现错误。

分类

一般iOS的单元测试分为内置的 XCTest 和一些第三方的测试框架。XCTest主要分为两部分Unit Test(单元测试) 和 UI Test(UI 测试)。

第三方的测试框架就比较多了,单元测试比较好的有KiwiQuick,UI测试有 KIFappium

目前我们只介绍iOS 内置的单元测试,第三方的测试框架有兴趣可以自己研究下。

XCTest使用

要使用XCTest需要我们在项目开始的时候选择引入单元测试的文件

在项目中使用单元测试_第1张图片
image

如果新建工程的时候没有选择单元测试也没关系,可以在之后添加单元测试的target进去

在项目中使用单元测试_第2张图片
image
在项目中使用单元测试_第3张图片
image

引入之后我们来看一下单元测试相关的方法

在项目中使用单元测试_第4张图片
image

使用@testable import 可以引入要测试的模块,即使是私有的方法也是可以调用的。

// 每次测试前调用,可以测试前创建一些测试需要用到的对象
func setup()
// 每次测试结束时调用
func tearDown()
// 测试用例,一般我们不直接在这个方法里边写测试用例,而是以 `test` 为开头创建一个测试方法
func testExample()
// 用来测试性能
func testPerformanceExample()

测试断言

大多时候我们都使用断言决定测试的结果,可以使用断言进行比较、判断表达式真假,强行失败等:

//通用断言
XCTAssert(expression: Bool, message: String)
//常用断言:
XCTAssertTrue(expression: Bool, message: String)
XCTAssertFalse(expression: Bool, message: String)
XCTAssertEqual(expression1: Equatable, expression2: Equatable, message: String)
XCTAssertNotEqual(expression1: Equatable, expression2: Equatable, message: String)
XCTAssertEqualWithAccuracy(expression1: FloatingPoint, expression2: FloatingPoint, accuracy: FloatingPoint, message: String)
XCTAssertNotEqualWithAccuracy(expression1: FloatingPoint, expression2: FloatingPoint, accuracy: FloatingPoint, message: String)
XCTAssertNil(expression: Any?, message: String)
XCTAssertNotNil(expression: Any?, message: String)

XCTFail(message: String) //直接Fail的断言

当我们想要测试一个方法有没有达到我们的预期的是时候:

在项目中使用单元测试_第5张图片
image

这里我有一个testInitializationCity()的用例,是想确定manager属性初始化后它的currentCity属性是不是正确的。

当我们写好测试的代码的时候就可以运行下看看测试是否能通过

直接点击小方块就可以运行单个的测试用例

在项目中使用单元测试_第6张图片
image

或者直接在导航栏操作点击右侧的运行按钮

在项目中使用单元测试_第7张图片
image

异步测试

当我们要测试一个异步的方法的时候,结果不能立即获得,这时候我们可以使用设置期望,然后设定等待时间的方式。

在项目中使用单元测试_第8张图片
image

当异步操作完成,并且满足我们的期望的时候,可以使用 exp.fulfill()来表示满足期望。如果不满足就会抛出我们设定的描述

在项目中使用单元测试_第9张图片
image

还可以通过expectationForNotification方法,来监听一个通知,如果在规定时间内正确收到通知则测试通过。

性能测试

性能测试主要使用func measure(_ block: @escaping () -> Swift.Void)方法,用于测试一组方法的执行时间,通过设置baseline(基准)和stddev(标准偏差)来判断方法是否能通过性能测试。

在项目中使用单元测试_第10张图片
image
在项目中使用单元测试_第11张图片
image

我们通过设置 Baseline来设置基准时间,然后Max STDDEV设置误差,在基准时间满足误差范围,就会测试通过。

项目使用CocoaPods管理时,单元测试报错解决

当在项目中使用CocoaPods时,使用单元测试时,必须为单元测试的框架也引入这些库,例如

# Uncomment the next line to define a global platform for your project
platform :ios, '8.1'

source 'http://repo.baichuan-ios.taobao.com/baichuanSDK/AliBCSpecs.git'
source 'https://github.com/CocoaPods/Specs.git'
source 'http://112.124.41.46/yougoods-ios/xgn.git'

target 'VLY' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!
  # Pods for VLY
  pod 'HandyJSON', '~> 1.6.1'
  pod 'Alamofire', '~> 4.4.0'
  pod 'FMDB', '~> 2.6.2'
  pod 'CryptoSwift’, '~> 0.6.8'
  pod 'SAMKeychain', '~> 1.5.2'
  pod 'MJRefresh', '~> 3.1.12'
  pod 'SnapKit', '~> 3.0.2'
  pod 'AMap3DMap-NO-IDFA', '~> 4.6.1'
  pod 'AMapLocation-NO-IDFA', '~> 2.3.1'
  pod 'Kingfisher', '~> 3.6.0'
  pod 'AliyunOSSiOS', '~> 2.6.0'
  pod 'UTDID', '~> 1.1.0.16'
  pod 'UMengAnalytics-NO-IDFA', '~> 4.2.5'
  pod 'tingyunApp', '~> 2.5.4'
  pod 'MBProgressHUD', '~> 1.0.0'
  pod 'Vine', '= 1.0.6'
  pod 'MediaPicker', '~> 1.1.4.5'
  pod 'FuckSwiftGen', '~> 1.0.0'
  target 'VLYTests' do
      inherit! :search_paths
      pod 'tingyunApp', '~> 2.5.4'
      # Pods for testing
  end
  
  target 'VLYUITests' do
      inherit! :search_paths
      # Pods for testing
  end
end

VLYTests target 引入这些第三方库,可以使用inherit! :search_paths的方式继承,但是有些库继承会失败,所以这时候继承失败的库就要单独再写出来引入了。

以上就是单元测试的基本使用方法,单元测试学会使用并不难,但是想要用好,就需要多下些功夫了,是相对比较难的,而且可能需要耗费蛮多时间,反正如果单元测试能用好,对我们项目的好处是很大的。

你可能感兴趣的:(在项目中使用单元测试)