热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

2015年iOS测试现状

本文由伯乐在线-nathanw翻译,dopcn校稿。未经许可,禁止转载!英文出处:www.mokacoding.com。欢迎加入翻译小组。几周前,我决定将将我在mokacoding

几周前,我决定将将我在 mokacoding 上的创作更多集中在单元测试与验收测试,自动化和生产效率上,主要在iOS领域。

相关深入文章可以看看“通过 CocoaPods 为 iOS 项目创建 Calabash 并构建配置”和“用终端运行 Xcode 测试”。

这周我们要回过头来看看,或者说是站在更高的角度审视单元测试和验收测试,以及在云端运行持续集成有哪些资源。

就像有人创建 walking skeleton 时会做的事情一样,我们也将先查看 Cocoa 和 Xcode 提供给开发者的工具,然后再看看能实现更好效果的开源库,最后整理出在云端持续集成环境运行测试的解决方案。

Xcode,测试开始的地方

伴随着 iOS 7 和 Xcode 5,苹果发布了 XCTest,一个简单而又强大的测试编写框架,使用了同 xUnit 一样的风格。

编写 XCTest 测试很简单,开发者在 Xcode 点击 ?U 运行测试便能持续不断地迅速获得反馈。

Xcode 还有一个叫“Test Navigator”的界面,它可以让我们看到所有测试点,包括在最后一次运行后的成功或失败状态。

技术分享

值得注意的是,红色为测试失败,绿色为测试通过。在不断迭代过程中颜色会给你很大帮助。

XCTest 已经高度集成在 Xcode 中,使用简单方便。这是它主要优点,也是缺点。XCTAssert 类 API 并不容易理解,也不灵活。从 Xcode 外边运行测试也没有你想象的那么简单。

在过去两年中,iOS 和 OS X 的单元测试框架已经变得越来越好,而验收测试这边反而没什么进步。

苹果提供了 UIAutomation 框架来编写 UI 自动化测试。UIAutomation 测试使用 Javascript 写成。允许用户使用代码驱动应用 UI 并给它的状态设置断言。尽管看上去很美好,使用 UIAutomation 其实是很繁琐的, Javascript API 也没有原生代码写成的单元测试那样强大。

这是 UIAutomation 测试的一个小片段。

1
2
3
4
5
UIATarget.localTarget().frontMostApp().navigationBar().buttons()["Add"].tap();
 
UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].cells()[0].elements()["Chocolate Cake"];
 
UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].scrollToElementWithPredicate("name beginswith ‘Turtle Pie‘");

你可以看到的,Javascript API 比 Foundation 中的那些更加冗长。再加上这种测试需要在 Instruments 中运行,你就可以想象使用这个框架是多么的不爽。

最后是苹果的 CI 解决方案:Xcode Bots。我们可以配置一个 Xcode Bot,在需要的时候触发他工作,例如运行我们的测试,Xcode Bots 可以存放在服务器端。

我承认我自己并没有用过 Xcode Bots,但是我获得的所有反馈都告诉我这个东西并不好用。

总结下,如今缺乏好奇心的开发者和大公司,可以只使用苹果的技术,组建一整套运行在CI的单元测试和验收测试。用于工作基本上是足够了。

如果你正在阅读本文,你可能充满了好奇心,那么让我们继续看看开源社区有那些资源。

开源单元测试框架

iOS 和 OS X 开源社区充满了各种大牛和有趣的项目。在写本文的时候,在 pod 上一共有 8625 个开源项目。

这些单元测试的开源库主要都是行为描述风格(xSpec),一定程度上也反映了测试风格的一种趋势,这风格来自于 Ruby 测试库的 RSpec, 主要是测试类的行为,而不是枚举方法。

Kiwi

Kiwi 是一个全栈式的,XCTest的代替品,支持行为描述句式。实例代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
describe(@"Team", ^{
  context(@"when newly created", ^{
    it(@"has a name", ^{
      id team = [Team team];
      [[team.name should] equal:@"Black Hawks"];
    });
 
    it(@"has 11 players", ^{
      id team = [Team team];
      [[[team should] have:11] players];
    });
  });
});

Kiwi 测试用例通常非常容易阅读和理解代码所想要测试的内容,他就像一个好的说明文档。

Kiwi 集成了一些测试方法 期望(expectations), 模拟对象 (mock),桩程序 (stub),甚至还支持异步测试。

Specta

Specter 跟 Kiwi 非常像,但是它使用了不同的架构。Kiwi 是庞大的代替品 ,Specta 优势则体现在模块化与组件化。这个库关心的唯一事情是编写和运行 xSpec 风格的测试,然后用户可以根据使用期望(expectations), 匹配(matching),模拟对象(mock)和桩程序(stub)的情况来补充相应模块。

我个人更喜欢这个库的设计,轻量级,包含的多个模块可以被结合在一起。

这是 Specta 行为描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SpecBegin(Thing)
 
describe(@"Thing", ^{
  it(@"should do stuff", ^{
    // This is an example block. Place your assertions here.
  });
 
  it(@"should do some stuff asynchronously", ^{
    waitUntil(^(DoneCallback done) {
      // Async example blocks need to invoke done() callback.
      done();
    });
  });
});

注意 it 执行的时候 blocks 是空的。留给库的使用者来用他们喜欢的工具填写。

说到工具,这里有一个库名单,他们都可以与 Specta 和 Kiwi 配合使用:

  • Expecta a matcher framework, expect(foo).to.equal(bar).
  • OCHamcrest another matcher framework, assertThat(foo, equalTo(bar)).
  • OCMock a mocking framework.
  • OCMockito another mocking framework.
  • OHTTPStubs a library to stub network requests, with block based syntax to match URLs.
  • Nocilla another library to stub network requests, with a nice chain-able API, stubRequest(@”POST”, ).withHeaders(…).withBody(…).

Quick

Quick 是一个新的测试框架,也相当炫酷的一个。主要代码都是用 Swift 写的,非常适合用新的语言写测试组件。

1
2
3
4
5
6
7
8
9
10
11
import Quick
 
class ThingSpec: QuickSpec {
  override func spec() {
    describe("a ‘Thing‘") {
      it("should do stuff) {
        //
      }
    }
  }
}

多亏了 Swift 的语法和闭包,Quick 的行为描述看起来比 Kiwi 和 Specta 的可读性更强。

和 Qucik 一起的 Nimble 是一个 matcher 库,它允许用户进行简洁地表达,例如 expect(10) > 2

无论是 Objective-C 还是 Switf,单个庞大框架或是你喜欢的库组成的组件,开源社区提供了大量有价值的测试框架,特别是专注于写简洁测试的,感谢有表达句法(expressive syntax)。

验收测试的开源库

苹果提供的官方工具中单元测试框架和验收测试框架的质量对比也反应在开源社区中。可能是因为 XCTest 为开源单元测试框架们提供了一个坚实的基础,而 UIAutomation 没有,所以我们只能选择一些非常规的方法。

KIF

KIF,保持函数式(Keep It Functional),这是一个用 Objective-C 写的框架,让我们使用 XCTest 编写验收测试,然后在 Xcode 运行,方式和我们在单元测试做的一样。

KIF 使用私有的 API 来获得视图层级,然后让我们使用 accessibility 标签值来视图查询与交互。

1
2
3
4
5
6
7
8
- (void)testSuccessfulLogin {
  [tester enterText:@"user@example.com" intoViewWithAccessibilityLabel:@"Login User Name"];
  [tester enterText:@"thisismypassword" intoViewWithAccessibilityLabel:@"Login Password"];
  [tester tapViewWithAccessibilityLabel:@"Log In"];
 
  // Verify that the login succeeded
  [tester waitForTappableViewWithAccessibilityLabel:@"Welcome"];
}

KIF比较不好的地方在于作者响应时间较慢。这不是批判,毕竟开源世界一切都是免费的,但我们都要赚钱糊口,可以理解作者用在这些项目上的时间是有限的。但是当整个框架的基础都非常难以使用,那么他的稳定性一定很低。

Subliminal

Subliminal 是一个类似 KIF 的 Objective-C 框架,集成了 XCTest。和 KIF 不同的是,SUbliminal 是写在 UIAutomation 上层,旨在为开发者隐藏它的复杂性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (void)testLogInSucceedsWithUsernameAndPassword {
  SLTextField *usernameField = [SLTextField elementWithAccessibilityLabel:@"username field"];
  SLTextField *passwordField = [SLTextField elementWithAccessibilityLabel:@"password field" isSecure:YES];
  SLElement *submitButton = [SLElement elementWithAccessibilityLabel:@"Submit"];
  SLElement *loginSpinner = [SLElement elementWithAccessibilityLabel:@"Logging in..."];
 
  NSString *username = @"Jeff", *password = @"foo";
  [usernameField setText:username];
  [passwordField setText:password];
 
  [submitButton tap];
 
  // wait for the login spinner to disappear
  SLAssertTrueWithTimeout([loginSpinner isInvalidOrInvisible], 3.0, @"Log-in was not successful.");
 
  NSString *successMessage = [NSString stringWithFormat:@"Hello, %@!", username];
  SLAssertTrue([[SLElement elementWithAccessibilityLabel:successMessage] isValid],
  @"Log-in did not succeed.");
 
  // Check the internal state of the app.
  SLAssertTrue(SLAskAppYesNo(isUserLoggedIn), @"User is not logged in.")
}

Subliminal 声明它可以测试应用内购警告,甚至能使 app 进入睡眠。这听起来很牛,但事实是,在我写本文的时候,该库最近的一次代码提交是 2014年9月,而且还有 13 活跃的 pull request,这些都是不好的信号。

Calabash

目前我们所说到的工具中,Calabash 是最原始的一个。它是一个 Ruby 包,使用 Cucumber 编写 BDD 风格的验收测试,现在由 Xamarin 维护。Xamarin 是一个用 C# 写 iOS 和 Android 应用的框架。语言会不会有点多!

不像 KIF 和 Subliminal,Calabash 完全不集成在 Xcode 中。我创建示例使用的是 Vim 和 Rake。

我们书写 Cucumber 特性,执行每一步,然后使用命令行测试。为了它能够工作,需要在应用内嵌入一个 HTTP 服务器,用于查询和驱动 UI。

不用说,这可能是一个很大坑。

Cucumber/Calabash 测试代码差不多是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# rating_a_stand.feature
 
Feature: Rating a stand
  Scenario: Find and rate a stand from the list
    Given I am on the foodstand list
    Then I should see a "rating" button
    And I should not see "Dixie Burger & Gumbo Soup"
 
# steps.rb
 
Given(/^I am on the foodstand list$/) do
  wait_for_element_exists "view marked:‘Foodstand‘"
end
 
Given(/^I should see a "([^"]*)" button$/) do |button_title|
  wait_for_element_exists "button marked:‘#{button_title}‘"
end
 
Given(/^I should not see "([^"]*)"$/) do |view_label|
  wait_for_element_does_not_exists "view marked:‘#{view_label}‘
end

Calabash 好的地方在于它是一种陈述式的测试,管理层会喜欢如果他们会读到这些测试的话。而且它可以兼容两个平台。

另一方面,工具链并不是非常强大。测试运行相对较慢,需要在 Cucumer,Ruby,Objective 之间持续交换,消耗相当多的时间。

就像单元测试,开源库提供了不同的选择,用于改进你的工作流。唯一不同的是这些工具没那么成熟,社区没那么活跃。

持续集成平台

为我们的项目套上好的测试工具,其最后一步是拥有持续集成。在开发者机器上运行测试并不能保证代码不会出错,毕竟其他团队成员会对代码进行更改。有个人来不断运行测试会更加安全。

不用说,最好的 CI 是在云端进行。配置维护一套 Jenkins 需要大量的时间。

CI 的选择会更多。这里列出一些支持 iOS 项目的主要 CI 服务。

  • Travis CI
  • Ship.io
  • Sauce Labs
  • Bitrise
  • Testdroid

它们之间的区别主要是在价格,上手容易程度,以及如何配置。例如 Travis CI 使用 .travis.yml文件定义所有的步骤,而 Bitrise 则图形界面,每个步骤都用 block 展示,并且这block可以被添加到进程。

上面这个列表可能并不全面,我可能落了一些。希望这个对于有兴趣写测试和 CI 的人是一个好的开始。

2015年iOS测试现状


推荐阅读
  • 本文探讨了程序员这一职业的本质,认为他们是专注于问题解决的专业人士。文章深入分析了他们的日常工作状态、个人品质以及面对挑战时的态度,强调了编程不仅是一项技术活动,更是个人成长和精神修炼的过程。 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 本文介绍了SIP(Session Initiation Protocol,会话发起协议)的基本概念、功能、消息格式及其实现机制。SIP是一种在IP网络上用于建立、管理和终止多媒体通信会话的应用层协议。 ... [详细]
  • 本文详细介绍了JQuery Mobile框架中特有的事件和方法,帮助开发者更好地理解和应用这些特性,提升移动Web开发的效率。 ... [详细]
  • 我的读书清单(持续更新)201705311.《一千零一夜》2006(四五年级)2.《中华上下五千年》2008(初一)3.《鲁滨孙漂流记》2008(初二)4.《钢铁是怎样炼成的》20 ... [详细]
  • 本文介绍了如何通过C#语言调用动态链接库(DLL)中的函数来实现IC卡的基本操作,包括初始化设备、设置密码模式、获取设备状态等,并详细展示了将TextBox中的数据写入IC卡的具体实现方法。 ... [详细]
  • 本文详细介绍了C++中的构造函数,包括其定义、特点以及如何通过构造函数进行对象的初始化。此外,还探讨了转换构造函数的概念及其在不同情境下的应用,以及如何避免不必要的隐式类型转换。 ... [详细]
  • 本文详细介绍了iOS应用的生命周期,包括各个状态及其转换过程中的关键方法调用。 ... [详细]
  • 本文将从基础概念入手,详细探讨SpringMVC框架中DispatcherServlet如何通过HandlerMapping进行请求分发,以及其背后的源码实现细节。 ... [详细]
  • 本文探讨了在一个物理隔离的环境中构建数据交换平台所面临的挑战,包括但不限于数据加密、传输监控及确保文件交换的安全性和可靠性。同时,作者结合自身项目经验,分享了项目规划、实施过程中的关键决策及其背后的思考。 ... [详细]
  • importjava.io.*;importjava.util.*;publicclass五子棋游戏{staticintm1;staticintn1;staticfinalintS ... [详细]
  • 解决Visual Studio Code中PHP Intelephense误报问题
    PHP作为一种高度灵活的编程语言,其代码结构可能导致Intelephense插件在某些情况下报告不必要的错误或警告。自1.3.3版本起,Intelephense引入了多个配置选项,允许用户根据具体的工作环境和编程风格调整这些诊断信息的显示。 ... [详细]
  • 深入解析WebP图片格式及其应用
    随着互联网技术的发展,无论是PC端还是移动端,图片数据流量占据了很大比重。尤其在高分辨率屏幕普及的背景下,如何在保证图片质量的同时减少文件大小,成为了亟待解决的问题。本文将详细介绍Google推出的WebP图片格式,探讨其在实际项目中的应用及优化策略。 ... [详细]
  • 在处理大数据量的SQL分页查询时,通常需要执行两次查询来分别获取数据和总记录数。本文介绍了一种优化方法,通过单次查询同时返回分页数据和总记录数,从而提高查询效率。 ... [详细]
  • 本文通过一个具体的实例,介绍如何利用TensorFlow框架来计算神经网络模型在多分类任务中的Top-K准确率。代码中包含了随机种子设置、模拟预测结果生成、真实标签生成以及准确率计算等步骤。 ... [详细]
author-avatar
开心小笨笨猪
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有