Tag: 测试

使用XCUITests更改设置

Xcode 9增加了编写测试的能力,而现在它可以与“设置”应用程序进行交互。 如果每个人都想禁用位置或将动态字体切换为大字体? -现在有可能。 首先,我们需要像普通应用程序一样午餐设置应用程序,并提供它的捆绑包标识符。 让settingsApp = XCUIApplication(bundleIdentifier:“ com.apple.Preferences”) settingsApp.launch() 您可以与设置进行交互,就像使用应用程序一样。 由于“ [MC] 从私人有效用户设置中读取”错误,目前无法使用交互记录。 我已经提出雷达来增加这种可能性。 假设我们要打开和关闭定位服务。 我们可以这样做: settingsApp.tables.cells.staticTexts [“ Privacy”]。tap() settingsApp.tables.cells.staticTexts [“位置服务”] .tap() 如果settingsApp.switches [“位置服务”] .isSelected { settingsApp.switches [“位置服务”] .tap() settingsApp.buttons [“关闭”] .tap() }其他{ settingsApp.switches [“位置服务”] .tap() } 最好在teardDown上终止设置,这样我们将在每次测试运行时进入主设置屏幕。 settingsApp.terminate() 这是测试的实际效果: 您可以在github上找到要使用的示例项目:https://github.com/PycKamil/XCUITestSettingsExample

TDD是“落后”

在向同事教授TDD时,经常会出现相同的问题: 我们从哪里开始开发软件? 这个问题导致了很多讨论和理解TDD的艰辛。 我看到了从哪里开始的不同方法,但是大多数情况下,人们倾向于使用用户界面。 这样做的原因是能够执行交互并查看他们是否实现了正确的行为。 在TDD中执行此操作非常繁琐。 您从一个按钮开始,然后检查它是否为nil。 好的,是这样……按下按钮时,我想查看用户搜索的电影列表。 嗯,我还没有测试,因为我还没有任何数据! 该怎么办? 一种选择是传入伪数据,并在每次添加一些代码时将其逐段替换为实际数据。 这似乎很好,直到您意识到需要大量工作并且开发速度缓慢。 另一种选择是不以用户界面开头。 而是从网络请求开始。 从这里开始,您的测试将确切知道预期的内容并正在测试实时数据,而不是模拟(当然,下一步是对请求进行存根,但我们还没有完成)。 编写完请求后,我们可以添加解析,然后可以添加存储等。通过这一切,我们知道我们拥有的工作代码不基于假设。 自下而上的一个问题是股东。 他们希望看到您软件中的更改,而他们看不到创建网络堆栈。 不要陷入模拟所有数据并仅创建用户界面以使股东满意的陷阱。 在某个时候,您将不得不编写其余的内容,然后他们将抱怨更多,因为开发速度很快,现在没有新内容了。 除了默认的TDD做法,这没什么别的主意: 从您所需的最小代码开始,并为此编写测试。 结论 让这个主意变得不那么容易。 它要求纪律首先编写测试,而不添加不必要的代码。 仍然遵循这一纪律并坚持下去将会产生巨大的成果,上面所写的想法只会帮助您入门。 实践TDD本身将得出这个结论。 如果不是这样,我很想听听! Next:Swift中的高级模拟 上一篇:联网怎么样?

使用Moya 101进行测试

Moya非常谨慎,以确保测试是小菜一碟。 但是,据某些人称,其测试文档有些分散。 因此,我决定写这篇文章,重点是与Moya进行测试。 我将尝试从Moya的文档中收集到的所有问题以及我自己的贡献来回答这里提出的所有问题。 最终,本文可以用作编写更认真的文档的起点¹。 在我们开始之前:我将假设您… 已经知道如何使用Moya。 如果没有,跳进去,很有趣! 有自己的TargetType 。 我将其称为APIService 。 不要指望本文教给您有关测试的知识。 我也不是高手。 知道(或可以理解)XCTest的一些非常基础的知识。 我选择的是……因为™ 。 准备? 存根 如您所知,在创建APIService时,需要为所有目标提供APIService 。 存入电话时将使用此数据。 但是,显然,如果没有您的明确要求,就不会发生这种替换。 您只需要很好地要求: ¹我实际上要敢于在非我的库中编写文档,然后等待有关本文的一些反馈。 我不是很精通它,或者在测试中。 但我渴望提供帮助。 期待着听到您的意见!

iOS版Travis CI

最近,我想为我的应用程序实现持续集成。 我想很多人和我偶然发现了Travis CI上的objc.io文章。 不幸的是,这篇文章已经过时了,它是从2013年11月开始的。 同时,自从撰写本文以来,Facebook的xctool项目中一直在讨论xctool是否要支持Xcode8。但是,我们已经在Xcode 9上了。与此同时,已经发生了很多变化,文章已过时。 我个人认为objc.io应该不时测试他们的文章,或者至少要提到所使用的技术无效或无法正常工作。 由于他们没有更新他们的文章,我觉得我应该发布更新。 因此,基本上改变的是xctool has some new commands, for example test has been replaced by run-tests 。 此外, xctool不再构建您的项目,我们必须退回到xcodebuild , xcbuild或Buck(Facebook的新项目)。 假设您知道如何使用GitHub帐户将项目链接到Travis CI,我将主要讨论.travis.yml文件。 我只强调了.travis.yml文件的一些区别。 您仍然需要在objc.io文章中添加仍然正确的其他元素。 如您所见,存在一些差异。 例如:(1)我们可以安全地将语言设置为Swift,如今,(2)应该仍然可以正常工作,但是我仍然更喜欢使用xctool 。 (3)完全是错误的, 这不再起作用 。 (4)这就是正确调用xctool ! 使用xcodebuild或您喜欢并且可能已经使用的任何其他构建系统来构建工作区。 然后使用xctool运行测试。 在第14行的摘要中,如果您将-scheme TravisExampleTests更改为-scheme TravisExampleTests ,则还可以免费运行UI测试。 这需要其他配置,因为以这种方式运行将导致断言失败: NSInternalInconsistencyException, “No target application path specified via test configuration” 。 […]

测试Marvel的View Code项目..具有100%的代码覆盖率!

在项目中采用视图代码确实可以帮助它变得更加模块化。 几周前,我写了一篇文章,展示了如何迁移使用情节提要+ xibs构建的Marvel项目来查看代码,您可以在此处进行检查。 在那篇文章中,我描述了这样做的一些好处,其中之一就是与测试有关。 视图代码更易于测试,因此,当您采用视图代码时,您的测试服会越来越多。 今天,我将展示如何为项目编写测试以及在此过程中进行的一些重构。 您可以在此处通过测试检查存储库。 **这个Marvel的项目是在一系列的帖子中创建的,如果您错过了查看的话。 为什么测试更容易? 首先,查看代码使您可以控制代码的初始化过程。 这似乎没什么大不了,但请相信我。 现在,您可以编写一个与给定类型一起使用的自定义初始化程序,这有几个好处: 您可以在测试环境中使用setter注入,例如,提供伪造的实现(模拟)而不是真实的实现。 这可以帮助您独立运行测试,稍后再介绍。 现在,您可以控制初始化过程,您可以使用let删除一些可选参数并将变量定义为常量。 语义上更正确,比方说您正在创建角色视图控制器。 现在,您可以强制要求有人在视图控制器初始化过程中提供字符,这很有意义。 经过所有的重构和测试编写,我设法将应用程序的代码覆盖率提高到100% 。 代码覆盖率本身不应达到某个特定数字。 而是应将其用作地图,该指南显示了可以在项目中改进的地方的提示。 在某种程度上,代码覆盖率的真正价值是回答这个问题, 接下来我要测试什么? 以同样的方式,您的测试应用于重构代码并使之更好。 更好的代码意味着: 更具模块化 更可重用 封装好 明确而单一的目的 易于开发的代码 易于维护的代码 测试之所以能够帮助您“使代码变得更好”,是因为它们使您可以从接口的角度来了解代码的调用者。 如果要在后台做很多事情,通常很难测试,因此需要重构。 有无视图代码..! 现在,让我们将在早期版本的项目中使用Storyboard + xibs进行的测试与在该版本中的视图代码进行比较。 这将使我们能够检查两种方法之间的好处和区别。 使用Storyboard进行CharacterViewController测试 使用查看代码的CharacterViewController测试 您现在可以看到,使用视图代码,我们可以摆脱以前用于获取视图控制器的许多样板代码。 以前,我们无法控制初始化过程,因此我们必须从情节提要中恢复它,并重复相同的旧配方。 好吧, 不再了! 第二个版本不需要测试不是从视图控制器给出字符的情况,因为现在它是init进程的参数,这意味着如果有人想要一个CharacterViewController,他们将需要为该字符提供一个字符。在里面。 CharactersViewController测试.. 现在我们可以控制视图控制器的初始化过程了,我们可以将apiManager作为视图控制器的参数来提供,使设置器注入变得轻而易举,同时使用let可以将控制器中apiManager的变量保持不变。 在没有视图代码的先前版本中,我们必须将其保留为var进行注入,将其返回时我们无法控制初始化。 没有查看代码.. 与查看代码.. 能够控制初始化过程是如此重要,它使您可以更好地控制代码! 您可以使用下面的视图代码检查对CharactersViewController的改进测试。 CharacterTableCell规格.. characterTableCell测试也得到了极大的增强,没有视图代码,我们不得不使用cellForRow方法从数据源中恢复它,这意味着我们不得不重复同样的方法,从情节提要中加载视图控制器。 不再! […]

单元测试中的存根网络调用

确保您知道您的回应 几年前,我被要求支持公司的其他分支机构。 他们的iOS开发人员很快就离开了,他正在开发的应用程序即将完成。 我去那儿修复了大约10个错误……它以50多个问题结束,但是我们都知道,这在开发过程中很正常。 尤其是当您有一位对利润非常挑剔的出色设计师时。 无论如何..我到了那里,想测试一些网络代码。 我以为我既年轻又年轻(大约一年前才开始使用Kiwi),所以我可以使用这些方法,然后继续前进。 我的一个同事不太喜欢这个主意。 她建议使用当前存在的依赖项,而不要引入新的依赖项(在此期间,我们使用的是XCTest,而不是Kiwi)。 那么她的解决方案是什么? 她已经在使用KIF,并且针对后端运行UI测试并不好玩。 而是使用OHHTTPStubs。 使用此库,您可以拦截网络请求并返回所需的任何内容。 我的猜测是,它在NSURL上使用方法刷新进行拦截,但是如果有库,为什么要自己做。 如何使用 编写拦截器非常容易。 只需指定要拦截的主机和路径并返回响应即可。 我倾向于在包含我的拦截器的OHHTTPStubs上使用类方法创建扩展。 响应是您的JSON对象。 根据要返回的内容,您可以使用库提供的初始化程序。 我还创建了一个匹配器,以便于检查是否调用了正确的网址。 OHHTTPStubs提供了一些,但是有时您必须编写自己的。 这是通过创建OHHTTPStubsTestBlock来完成的。 这是一个闭包,将在其中传递一个RequestObject并返回一个Bool。 与往常一样,要设置我们的套件,我们可以使用beforeEach或beforeSuite。 只是不要忘记事后清理! 所以请不要忘记: OHHTTPStubs.removeAllStubs() 结论 我喜欢这个图书馆。 这是您进行单元测试所需的全部。 几个月前,我向团队介绍了它,从那时起,我们的网络测试就针对OHHTTPStubs进行了。 使用OHHTTPStubs使我们能够测试整个应用程序,而不必在生产系统中引入任何测试代码。 这样,我们可以确定,只要后端api不变,我们的应用程序就会按照我们期望的方式运行。 下一步:TDD向后 上一篇:测试苹果MVC

我应该使用多少个测试?

我在开始撰写此博客时就对如何提高应用程序质量进行了解释。 在途中,我们遇到了许多不同类型的测试。 但是,我们应该对每种类型的应用程序投资多少? 一如既往,需要平衡。 这次是关于我们可以投资多少与将创造多少价值(不是总是这样)。 因此,让我们详细看一下。 单元测试 我们已经对单元测试进行了很多研究。 如何在Objective-C,Swift中做到这一点以及如何测试Apple的MVC(测试UIElements时不要忘记在UIViewController上调用controller.view)。 单元测试的优势是什么? 快速 可靠(如果操作正确;) 涵盖很多部分 具有所有优势,还有什么要错过的? 他们是孤立的 不要测试零件是否装配在一起 最重要的是他们要快。 不论是10还是1000,都没关系。它们在不到几秒钟的时间内运行。 开发人员没有理由在提交更改之前不运行它们。 这很简单。 我们拥有的越多越好。 这也是我们在TDD中使用它们的原因。 确保独立编写它们。 不要使用数据库或网络。 而是存根吧! UI测试 UI测试也是一个主题。 我们已经看到了多个框架来实现它们,以及如何使它们独立于任何后端。 优点: 测试组件 您可以将它们用于验收测试 它们的行为类似于用户 与往常一样,您可以期望它们有缺点: 慢 脆弱(对应用程序的每次更改都会破坏它们) 慢(我已经提到过吗?) UI测试需要大量维护。 它们可能会随时中断,即使只是由于模拟器无法连接到Xcode也是如此。 因此,它们显示的每一次失败,可能都不是您应用程序中的错误。 您需要对其进行调查。 最重要的是,它们运行非常缓慢。 即使当告诉他们不要在测试开始时重新启动应用程序,使用模拟后端并删除动画(您仍然不应该这样做)时,它们也会永远占用。 目前,我们的50个测试需要15分钟以上的时间才能运行。 每次更改后,没有开发人员会这样做。 因此,您的CI需要。 拥有它们真是太好了。 但是请注意,它们需要大量工作。 由于测试很慢,因此不应有比单元测试多的测试。 验收测试 我们已经研究了无UI的验收测试。 使用这种类型可以实现令人难以置信的目标。 他们甚至可以帮助您与客户合作并以更精确的方式确定需求(如果您想了解与客户合作的方式,请查看BDD)。 那么为什么要使用它们: 快速(与UI测试相比) 测试整合 […]

在Swift中完善自定义断言

单元测试很棒,不是吗? 它不仅可以帮助您改进代码,而且可以确保下次更改它时不会弄乱任何东西。 测试的不利之处在于编写测试很容易,最终导致阅读困难! 在这里,我将介绍一些有用的技巧,这些技巧可以使您更容易阅读和理解单元测试代码。 断言及其使用 如果您之前没有编写过测试,则可能没有看到典型的测试断言。 断言(就像软件开发中的许多事物一样!)具有多种形状和大小,但是大多数情况下,它们是一段检查(或断言 )某些东西的代码。 if语句实际上是一个断言,在下面的示例中,我们断言该数组不为空: 如果imagesArray.isEmpty == false { //在这里做点事 } 在测试中,断言是单元测试的关键点-我们使用它们来断言 (或检查)我们的逻辑是否为我们提供了预期的结果: func testTwoMultipliedByTwoIsFour(){ 让计算器= Calculator() 让结果= Calculator.multiply(2,by:2) XCTAssertEqual(结果,4) } 在上述情况下,行XCTAssertEqual(result, 4)是断言—我们断言结果是4。 您可以在这里找到每个XCTAssert方法的完整描述。 在下面的演示中,我们可以看到样本测试失败时的外观。 您可以使用XCTFail()始终触发失败-在这种情况下,如果我们有一个if let可能无法通过,这很有用。 重要的一点是Xcode中的测试默认通过 ,因此我们必须记住在计为失败的分支上显式失败。 但是,这里的断言虽然很详细,但占用的行数却是其余测试的两倍! 让我们提取一个自定义断言以使其更具可读性。 定制断言 我们可以编写自己的自定义断言,这在断言可能变得复杂或最终导致在测试之间复制断言并实践三击规则的情况下非常有用。 我们可以提取断言,如下所示。 这使断言在测试方法本身中更小,并且还使我们对实际检查的内容有了更好的了解,而不必费力检查两个if let语句。 我们的断言现在可以正常工作。 但奇怪的是,断言失败不再显示在测试中,而是显示在我们的辅助方法中。 在运行测试时,这很烦人,因为您必须多花一些时间才能发现错误所在。 当多个测试使用相同的断言时,这确实很烦人,因为它们都在同一行上使断言失败! 我们想在调用自定义断言的地方显示失败,但是当前在我们的自定义断言的XCT函数显示失败。 幸运的是,我们可以改变这一点。 有些人会更喜欢在其自定义断言函数前加上XCT前缀,以使其看起来像内置断言方法,例如XCTAssertEquals(_,_) 。 通常不建议使用其他框架的前缀,但可以帮助您更快地在自动完成结果中找到自定义断言。 寻找最适合您的团队的东西。 更改显示断言的位置 我们有一种方法可以指出断言失败,使其看起来像来自调用自定义断言方法的位置,而不是来自其内部。 每个XCT函数都带有两个方便的默认参数-用于指示将红叉放在Xcode中的位置以及在哪里显示错误消息。 它们是file和line ,并且有两个对应的特殊“宏” […]

iOS快照测试

为iOS应用程序的用户界面编写测试非常麻烦。 由于进行基于视图的测试很困难,许多人不愿编写这些测试。 不幸的是,直到最近我还是遇到了验证我的观点的不同状态的问题。 为了实际查看结果,我需要在修改视图后多次运行该应用程序,这花费了很多时间。 因此,我试图寻求一种更有效的方式来处理这种情况,并且找到了一个完美的解决方案— FBSnapshotTestCase 。 它能做什么 快照测试用例采用已配置的UIView,并将其呈现为其内容的图像快照。 它将快照与存储在我的源代码存储库中的参考图像进行比较,如果两个图像不匹配,它将创建另一个参考图像。 通过将视图和现有快照都绘制到两个CGContextRef ,并使用C函数memcmp()对它们进行内存比较,进行比较。 这使其非常快。 安装与设置 按照他们在GitHub页面上的说明,我将pod ‘FBSnapshotTestCase’添加到pod ‘FBSnapshotTestCase’的测试目标中。 另外,推荐的设置参考目录的方法是在我的方案中定义FB_REFERENCE_IMAGE_DIR 。 这应该指向我要存储参考图像的目录。 示例值为$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages 。 很方便吧? 让我们开始编写一些代码。 实作 为了演示如何利用FBSnapshotTestCase的优势,我创建了一个具有两种不同状态的简单视图控制器:空和正常。 一方面,当视图控制器的状态设置为空时,它应该显示一个文本标签。 另一方面,视图控制器在状态正常时应显示字符串列表。 enum State { case empty case normal([String]) } 让我们编写一些测试来验证它们。 首先,子类FBSnapshotTestCase而不是XCTestCase。 然后将recordMode = true添加到setup方法中。 它将使宏记录新的屏幕截图,而不是对照参考图像检查结果。 最后,添加以下两个测试功能,以存储我的视图控制器的图像并运行测试。 func testViewControllerEmpty() { let vc = ViewController() FBSnapshotVerifyView(vc.view) } func testViewControllerNormal() { […]

Swift —测试驱动开发(TDD)

本文是同时介绍TDD和多个CI概念的指南的一部分。 您可以在 此处 查看介绍性文章 。 代码测试是开发中至关重要的部分,以确保您编写的代码既可以执行预期的工作,又可以确保将来的更改不会破坏过去的工作(眨眼眨眼的持续集成)。 TDD,即测试驱动开发,它不仅是一个时髦的词,而且是一种非常有趣且易于使用的开发方法。 有了它,您应该首先编写测试,然后再编写使它们通过的代码: 编写测试(该测试将失败,因为您还没有代码!) 编写最少的代码以使测试通过 进一步增强您刚才编写的代码的测试 重构代码以使新测试通过 在添加测试和重构代码之间进行迭代,直到达到所需的功能和代码质量为止。 为了向自己介绍TDD方法,我遵循了Yvette Cook的TDD指南,因此您应该很清楚地解释该概念,并逐步指导您实施示例项目。 有几个吊舱可以使测试过程更加简化并简化编写测试的任务。 他们是: 快 敏捷 因此,接下来,我将展示您可以对它们进行哪些使用: 将两个Pod导入到项目中: 2.从以下位置更改标题: 至 3.代码在spec()函数中运行: 4.用beforeEach块替换setUp()块: 5.使用Nimble,我们可以使用更易于阅读的方法编写测试。 例如: 变成: Nimble不仅易于编写,而且还赋予您更多表达结果的自由,并且还建立在其他XCTAssert功能的基础上(例如,在测试网络请求时,指定异步期望非常简单)。 请查看Nimble的文档以获取更多信息。 您可以在下面找到进一步的比较: 而旧的(如果失败的话)将不会显示文本错误消息(除非我们指定自定义消息,例如XCTAssert(1 == 2, “your custom error message here”) ,它会采用Nimble方法,它将自动使用在it(“message”)标头中指定的描述。 通过使用这些Pod,我认为我的测试不仅易于编写,而且最终也易于阅读(因此,将来可以根据需要进行更新)。 我打算在我现在开始使用的另外两个Pod上写一篇单独的文章,使您可以用更少的代码以不同的方式测试UI🙂现在,您可以检查他们的github页面: 敏捷快照 KIF 确立了测试的重要性之后,接下来的系列文章现在将重点介绍CI方法:它的重要性以及如何在XCode,Swift项目中将其付诸实践。 在这里检查。