iOS中的单元测试

第3部分:快速灵活的测试

前言

我打算编写完整的iOS单元测试系列。 您可以在下面的链接中找到成品。 快乐阅读🙂

第1部分:为什么在开发应用程序时需要进行单元测试?

第2部分:我的第一个单元测试

第3部分:快速/灵活的干净测试

第4部分:如何处理上下文

第5部分:良好做法

第6部分:单元测试,Jenkins和SonarQube一起[待撰写]


借助XCTest框架,您已经可以为应用程序编写所有可能的单元测试。 但是,一旦您做了很多测试用例,并且在测试类中有多个上下文,您就会发现使用XCTest并不是那么酷。 您可能会对使用Quick&Nimble感兴趣。 这两个框架(主要是Quick)将帮助您组织测试类中的测试,以使其更清晰,更易于阅读并且更容易在一个测试类中具有多个测试上下文。 使用Quick,您将为编写异步功能测试感到更加自在。

将Quick&Nimble集成到项目中的最简单方法是使用可可豆荚或依赖管理,例如Carthage甚至Swift Package Manager(Quick&Nimble支持这3种方法)。

如果与CocoaPods一起使用,请在项目根文件夹的终端中运行pod init ,以为项目初始化Cocoa Pods。 然后使用任何文本编辑器添加Quick&Nimble,如下所示:

最后,运行pod installpod update安装那些框架。 完成后,打开项目的.xcworkspace而不是.xcodeproject

考虑让一个Translator类从给定的键中获取本地化的字符串。 该翻译器能够处理多种语言,并以所选语言返回正确的文本。

如果我们使用XCTest为该类编写单元测试,我们将具有以下内容:

 导入XCTestclass转换器XCTests:XCTestCase { 
覆盖func setUp(){
//当我们有1个测试上下文时,此函数很有用,或者我们可以使用它来初始化公共上下文
}

func testSetupTranslator(){
让翻译器= Translator()
让yesButton = translator.message(“ yes_button”)

XCTAssertNotNil(yesButton,“应该能够获得有效的本地化字符串”)
XCTAssertEqual(yesButton,“是”,“应该使用英语作为默认语言”)
}

func testTranslationInFrench(){
让翻译器= Translator()
translator.setUp(“ fr”)

让yesButton = translator.message(“ yes_button”)
让noButton = translator.message(“ no_button”)

XCTAssertNotNil(yesButton,“应该能够获得有效的本地化字符串”)
XCTAssertNotNil(noButton,“应该能够获得有效的本地化字符串”)
XCTAssertEqual(yesButton,“ Oui”,“ yesButton的法语翻译是'Oui'”)
XCTAssertEqual(noButton,“ Non”,“法语的yesButton的翻译为'Non'”)
}
}

当我们用Quick编写它时,

 快速导入 
导入Nimble @ testable导入TestingToDummies
类TranslatorTests:QuickSpec {
覆盖func spec(){
describe(“翻译员”){
var translator:翻译器?

context(“正在初始化”){
beforeEach {
译者=译者()
}

it(“应该能够正确初始化”){
Expect(translator).notTo(beNil())
}

它(“应使用英语作为默认语言”){
Expect(translator?.message(“ yes_button”))==“是”
}
}

上下文(“翻译为法语”){
beforeEach {
译者=译者()
translator?.setUp(“ fr”)
}

它(“应返回法语文本”){
让yesButtonTitle =翻译器?.message(“ yes_button”)
Expect(yesButtonTitle)==“ Oui”

让noButtonTitle =翻译器吗?.message(“ no_button”)
Expect(noButtonTitle)==“非”
}
}
}
}}

您会看到在Quick test类中,我们可能不得不编写更多代码。 但是,这些额外的代码使测试用例井井有条,非常清晰。 当测试失败时,我们可以立即看到失败的原因以及在哪种情况下。 因此,编写测试不仅有帮助,而且在读取和维护测试时也有帮助。

当您运行那些Quick测试时,您将在测试报告中看到,所有it("should do something") {}都被转换为带有完整消息的测试用例。 因此,通常,测试类的结构是

  describe(“ given a”){ 
context(“ when b”){
beforeEach {
//准备上下文
}

它(“应该/要c”){
Expect(true).to(beTrue())
}
}
}

通过将Nimble与Quick结合使用,我们可以使用Nimble expect()语句使assertion检查更加自然。

beforeEach {}块确保在每次测试(由it() {}块给出)之前,执行一些代码以准备上下文。

使用Quick / Nimble更加轻松地编写异步功能测试。 不必创建期望并在满足 期望时调用fullfill() ,我们只需使用eventually assert方法调用expect()语句即可。 使用此方法时,请测试用例,直到获得所需数据或等待超时为止。

 快速导入 
导入Nimbleclass NetworkProviderQuickTests:QuickSpec {
覆盖func spec(){
describe(“ NetworkProvider”){
context(“服务启动并运行时”){
vardownloadedData:数据?
beforeEach {
//这里,我们应该使用SubClass / Mock和Stubs来消除对网络调用的依赖。
}

它(“应该能够正确获取服务器配置数据”){
NetworkProvider.getServerConfigData({
downloadedData =数据
})

期望(downloadedData).toNotEventually(beNil())
}
}
}
}
}

现在,如果您开始喜欢Quick,您可能会怀疑我们是否应该仅使用Quick编写/重写测试。 我的建议是:“同时使用它们” 。 如果您为没有异步代码的小类编写测试,则可以在XCTest中编写,而对于其他类或异步方法,请使用Quick / Nimble。 当然,Quick也适合小班学习,但是在这种情况下使用XCTest可以节省一些时间来编写单元测试。

要了解有关Quick / Nimble的更多信息,可以看一下该框架的github:

快速/快速

Swift(和Objective-C)测试框架。 通过在GitHub上创建一个帐户来促进快速开发。

github.com

您也可以在我的git中的这篇文章示例中找到代码:https://bitbucket.org/haduyenhoa/testingfordummies


希望您喜欢阅读。 在下一篇关于单元测试中的Mock,SubClass和Stubs技术的文章中再见。

第4部分已准备在这里:https://medium.com/@haduyenhoa/unit-testing-in-ios-3259deb81694