Tag: 测试

XCUITest的机器人模式测试

在iOS上使用机器人图案 我最近在iOSDevUK上发表演讲,概述了我们如何在Capital One测试我们的旗舰iOS应用程序。 我被问到的最常见的跟进问题是关于使用机器人图案 。 我在幻灯片中简要介绍了机器人模式,但显然这是其他人有兴趣了解的更多信息 机器人图案是由Square的Jake Wharton设计的,用于在Kotlin进行测试。 结果,许多可用信息都集中在Kotlin和Espresso测试上。 在线使用iOS的机器人模式的知识很少。 但是,Capital One UK Mobile团队选择使用机器人图案,因为这意味着我们的Android和iOS测试之间采用一致的方法。 这是iOS应用程式的运作方式。 为什么要使用机器人图案 编写XCUI测试时,使用机器人模式的三个主要原因。 易于理解 我们来自Calabash的XCUITests,我们的测试是用Cucumber编写的。 黄瓜接近自然语言。 这意味着您可以快速,轻松地阅读和理解所测试的内容,而无需确切了解测试的工作方式。 用本机代码编写测试,知道要测试的内容和没有测试的内容已经有了一条学习曲线。 重用代码 通过将我们的测试分为多个步骤,每个实现步骤都可以根据需要重复使用多次。 如果您的应用在执行任何操作之前具有登录屏幕,则每个测试的设置很多。 取而代之的是,您只需每次调用​​login(),然后继续进行测试的更具体区域。 如果确实需要做一些不同的事情,可以将参数传递给函数。 隔离实施细节 无论您的应用程序使用哪种架构,您的目标都是单一责任原则。 坚持这样做可以使您以新的实现将对象切换为新对象,同时仍保持对象的核心功能。 这使得代码更易于维护,测试和改进。 那么,为什么您的测试应该有所不同? 杰克·沃顿(Jake Wharton)将其描述为将“内容”与“方法”分开。 您的测试仅应关注“什么”,这意味着,如果您的视图改变了事物在屏幕上的显示或发生方式,则无需更改整个测试套件。 编写一个XCUITest 假设我们正在为Apple的内置Messages应用程序编写UI测试。 如果您从暂停状态加载应用程序,则会在屏幕顶部看到一个大标题“消息”和一个用于创建新消息的按钮。 假设我们正在测试点击此按钮,然后使用iMessage向用户发送新消息。 我们的XCUITest可能看起来像这样: func test_sendNewiMessage(){ 让app = XCUIApplication() app.launch() app.buttons [“ new_message”]。tap() 让newMessage = app.staticTexts [“新消息”] let谓词= NSPredicate(格式:“存在== […]

开始进行Swift编程第17部分-测试

在上一篇文章中,我们讨论了inout ,lazy以及getter和setter。 开始进行Swift编程第16部分-inout,Lazy,Getters和Setters 之前,我们介绍了使用泛型和枚举进行闭包。 medium.com 在本文中,我们将重点放在编写测试上。 您可能会认为这是可选的,因为它不会执行您的应用附带的任何逻辑。 如果您这样想,您将无法通过面试。 测试很重要,每当我听到它时就会想到一个术语。 测试驱动开发(TDD) 。 测试驱动的开发是编写应用程序的一种流行方法,其公式很容易记住。 编写一个失败的测试用例。 编写足够的代码,不再需要通过测试。 测试以确保案件通过。 还有其他测试方法。 您可以使用简单的打印语句来显示一段代码的前后结果,这是一种可以测试的好方法。 您还可以运行您的应用程序,以确保一切正常,这是测试您可能仍会做的最基本的最小方法。 我将仅在本文中介绍TDD。 在开始之前,我想提出两个新术语。 测试率和代码覆盖率 。 测试比率-比率是代码行数与编写的测试数的比率。 许多人会说应该用1:3的3个测试来测试1行代码。 代码覆盖率-涉及已测试的代码量的百分比。 许多IDE将提供代码覆盖视图,该视图根据测试状态突出显示代码。 绿色表示需要测试,红色表示没有测试。 尽管我应该默认像其他所有人一样“测试所有内容”,但我不会。 您不需要走极端,包括Swift或其他包含测试的库中包含的测试功能。 我不会为打印语句或其他一些静态方法(如Date.init() 。 实际上,您只需要测试您的代码即可,其他人的代码不包括测试。 我们编写测试的方式看起来像这样: 在第二轮中,我们的性能提高了39%,但没有任何变化。 这是因为优化已经存在,而我们只是重复使用了它们。 这是设置新基准的好地方,因此我们单击“编辑”,然后接受新基准并保存。 在随后的运行中,我发现在不更改代码行的情况下,变差了6%,好了0%,好了2%和好了7%。 这对我们来说是一个很好的基准。 在这里,我们可以进行更改,然后重新测试我们的测量,以查看是否使情况变好或变坏。 虽然没有严格的准则来指导什么是好的优化,但我认为保持10次测量(100次运行)中始终更好的任何更改。 如果在前几次运行中效果明显好些,我将保留更新的代码。 在测试方面,我们在上文中谈到了单元测试。 还有一个常规测试,它可以测试您应用程序的整体功能是否正常运行。 UI测试是涵盖您的UI的另一种测试,但是由于本教程只是基础知识,因此不在本文讨论范围之内。 最后,还有用户接受测试(UAT),它可以确保用户喜欢他们所拥有的东西。 这通常是由质量检查小组和业务部门或最终用户的特定受众群体完成的(了解有关TestFlight的信息)。 它使您可以在应用程序上投放更多方案以进行进一步测试,并在应用程序上线时将有关“我如何_________?”的问题保留下来。 我们了解了测试的基础知识,以及它如何帮助您编写更好的代码,它在开发周期中的重要性以及如何衡量您自己的代码的性能。 进一步的测试涉及使用Xcode Instruments,您可以在其中测量内存,CPU和磁盘(I / O)的使用情况,但是它更为先进。 确保为应用程序编写了良好的测试,以便您始终知道它会按预期运行。 接下来是模型视图控制器体系结构。 模型视图控制器(MVC)被广泛地用于教会新开发人员如何进行编码。 […]

生产中的断言

后端工程师确切地知道他们的服务正在发生什么。 他们实时了解其QPS,内存占用量,错误率和CPU利用率。 如果出现严重错误,它们甚至会自动进行分页,因此他们可以快速响应。 不幸的是,iOS工程师通常只有崩溃报告以及一些产品指标。 通常,我们会在用户报告错误时或更糟地在用户发布不正确评论时了解错误。 我们可以做得更好。 断言是条件检查,可确保您的代码按预期运行。 可能,您的代码库中已经有一些。 他们检查永远不会失败的条件,如果失败,则表明代码中存在严重错误 。 但是,断言在生产中已被删除,在现实世界中没有任何影响。 在我从事的每个项目中,我都添加了一个自定义Log类型,该类型使断言报告生产中的错误。 大多数崩溃报告框架都有报告非致命错误的能力,因此实施此操作很简单。 这是使用Crashlytics的示例: 枚举 Log { 静态 函数断言 #if调试 Swift.assert(condition(),message(),file:file,line:line) #其他 如果 !condition(){ 让域= message() let error = NSError(domain:domain,code:domain.hashValue,userInfo: nil ) Crashlytics.sharedInstance()。recordError(错误) } #万一 } 静态 函数 assertFailure ( _消息: @autoclosure ()->字符串,文件:StaticString = #file ,行:UInt = #line ){ Log.assert( false ,message,file:file,line:line) } } 在DEBUG […]

使用给定的When Then模式在Swift中进行测试

使用像Quick这样的spec测试框架很不错,它可以启用BDD样式。 describe(““文档”目录”){ 它(“拥有开始所需的一切”){ 让节= Directory(“文档”).sections Expect(section).to(contain(“包含快速示例和示例组的组织测试”)) Expect(section).to(contain(“快速安装”)) } context(“如果没有您要的东西,”){ 它(“需要更新”){ 让你=你(真棒:真) 期望{you.submittedAnIssue}。最终到达(beTruthy()) } } } 但是,如果您不想使用其他框架,并且希望尽可能地靠近Apple SDK,可以参考以下提示。 这是我非常喜欢“单元测试的艺术”的书。 如果您不介意下划线,则可以遵循UnitOfWork_StateUnderTest_ExpectedBehavior结构 func testSum_NegativeNumberAs1stParam_ExceptionThrown() func testSum_NegativeNumberAs2ndParam_ExceptionThrown() func testSum_simpleValues_Calculated() 这是来自BDD的,并且在Cucumber中实践了很多。 您可以在martinfowler.com/bliki/GivenWhenThen.html上了解更多信息。 首先,向XCTestCase添加更多扩展 导入XCTestextension XCTestCase { 给定的func(_说明:字符串,闭包:()引发->无效)引发{ 尝试闭包() } func when(_描述:字符串,闭包:()throws-> Void)throws { 尝试闭包() } func then(_描述:字符串,闭包:()throws-> Void)throws { 尝试闭包() } } 然后,为了进行测试,只需遵循given when then func testRemoveObject()引发{ 尝试给定(“设置为存储”){ 尝试storage.setObject(testObject,forKey:key) }试试when(“从存储中删除对象”){ […]

在Android和Mac上使用IPV6测试您的应用

苹果公司要求提供的广告,所有新提交的应用程序都必须经过测试并与IPV6网络兼容。 在线上已经有很多方法可以使用2个iPhones和Mac测试应用程序。 今天,我将向您展示一种使用Android和Mac设置IPV6网络的方法。 步骤1:为macOS安装驱动程序 MacOS不支持本地USB绑定模式来访问Internet,因此您必须安装驱动程序才能启用此功能。 从http://joshuawise.com/downloads/HoRNDIS-rel8.pkg(MacOS 10.11及更高版本)下载此文件,安装并重新启动。 注意:如果您正在运行旧版本的macOS,请访​​问http://www.joshuawise.com/horndis以下载正确的版本。 步骤2:在Android手机上安装 对于Android移动设备,请在您的Android移动USB tethering上找到USB tethering并启用它。 不同品牌在这里的设置可能会有所不同。 对我来说,我使用的是华为伴侣9: 第3步 :使用USB电缆将Android手机插入Mac。 将移动设备与Mac连接后,它将要求USB调试,然后选中“始终允许”,同样,不同品牌的产品可能会带有稍微不同的消息。 现在,mac能够使用USB电缆通过android与新网络连接。 在您的Mac上,打开“系统偏好设置”,按住选项并单击“共享”: 然后,您将在新窗口中找到“创建NAT64网络”,除非按住选项键,否则它将不会显示。 确保已选中 步骤4(最后一步) :拿出您的iPhone。 现在,您可以使用IPV6网络测试该应用了。

如何在Xcode中构建命令行应用

我最近在Xcode中为命令行创建了一个代码练习,但是遇到了很多配置问题。 最后,我能够构建两个目录,一个目录用于可执行文件,另一个目录用于测试并容纳所有代码。 在本快速教程中,我将引导您通过Terminal设置命令行项目。 这将使用Swift Package Manager,因此我将使用它生成的默认代码。 跳到底部,可以查看有关如何允许用户输入.txt文件名并允许Terminal打印其内容的非常快速的教程。 本文使用: Xcode版本9.2 Apple Swift版本4.0.3 首先,打开两个终端窗口并输入以下内容: mkdir CommandLineAppDirectory cd CommandLineAppDirectory / mkdir CommandLineApp mkdir CommandLineAppExe 到目前为止,非常简单,设置一个目录文件夹,导航到其中,并创建两个文件夹,其中一个附加了Exe,这样我们就知道哪个是可执行文件。 接下来,让我们设置我们的CommandLineApp。 我们将最后保存可执行文件。 cd CommandLineApp / swift package init –type库 快速测试 迅捷包generate-xcodeproj 打开CommandLineApp.xcodeproj / Swift Package Manager的库包设置了使球运转所需的一切。 它将为您提供Package.swift文件,Sources目录和Tests目录。 swift test将构建并测试您的项目,因此您可以通过命令行从根目录进行测试。 生成Xcode项目并打开它后,便可以使用⌘+ U进行构建和测试。 它会自动具有一个示例测试和主文件,供您查看它的工作原理。 打开CommandLineApp.swift文件并添加一些公共级别的代码,以便Exe可以访问它。 公共结构CommandLineApp { public var text =“您好,世界! 我已经成功创建了一个可测试的项目!” public init(){}} 现在我们有了要使用的文件,我们将初始化一个git […]

我如何发现1500名名人的大量信息泄露

在我们进入细节之前,只需要澄清一些事情: 我今天写这篇文章的原因是为了通知更多的质量检查工程师,他们应该更加谨慎地工作,并专注于许多事情。 不要忘记信息安全方面。 2.我有道德地砍。 没有个人利益。 虽然,我相信黑客应该为他们的贡献而获得积极的奖励。 不久前,这个有趣的故事发生在我身上。 在业余时间,我在youtube上观看英语视频博客。 在其中一个vlog中,我注意到了一个非常有趣的应用程序。 那是iOS设备的本机应用程序。 那人迅速显示了出来。 他告诉人们,这如何使他的生活更轻松,从而可以在世界任何地方订购赞助项目。 老实说,我有点喜欢这家公司。 而且我无法通过此申请。 首先,有必要说此应用程序放置在特殊的网页上。 以特殊Beta版本的形式。 下载数量很少。 对于android设备,下载数量接近1000–5000。 但这足以解决问题的严重性。 实际上,有很多问题,但首先要解决。 首先,我研究了应用程序如何与服务器端通信。 而且,最重要的是,它与哪个服务器一起工作。 令人惊讶的是,我在那里没有找到HTTPS协议。 这已经很奇怪了。 确定目标之后,我必须选择服务器中的漏洞。 但是最后,我遇到了一个没有受到暴力攻击保护的登录表单。 强制暴力…当然,我没有变得无礼。 毕竟,现在我生活在一个甚至连洪流都受到严厉惩罚的国家。 如果我进行此类攻击,那不是最正确的举动。 虽然没有恶意。 简而言之,无论您居住在哪个国家/地区,我们通常都会记住大约272条俄罗斯法律。 当我启动应用程序时,我发现了密码字段。 当然,我们不知道密码。 所以过了几天。 我从早上到晚上都沉迷于主要工作。 而且几乎没有时间做某事。 然后该应用程序提醒自己。 他给我发送了推送通知。 这不仅仅是通知。 这是有关新发表文章的信息性消息。 带有本文标题的本身来自内部系统。 它立即使我更加仔细地查看了该应用程序。 首先,无法轻易地将通知发送给未经授权的用户。 毕竟,我从未登录过应用程序。 我刚打开它并移到后台。 其次,我从内部系统收到了通知文本。 而且我根本无法访问该系统。 我考虑的第一件事-也许我对系统有一个“令牌”,我可以重复使用它来从内部系统中读取内容。 一切都按照我的想法。 像那样。 实际上,比我想象的要糟糕得多。 启动应用程序时,它会向内部系统发送一个请求,以读取需要显示的数据。 来自应用程序的第一个请求落入401错误。 从原则上讲,这是合理的。 毕竟,我们是未经授权的用户。 […]

使用Swift协议提高代码可测试性

作为开发人员,我们最大的挑战之一是实现高代码可测试性。 这些测试对于确保您开发的代码可以正常工作,并且在添加新功能时没有任何损坏方面非常有用。 另外,当您在团队中工作时,会有很多人在修改项目。 因此,确保代码的完整性也很重要。 有很多测试,但是它们不应该是有问题的或复杂的。 那么,为什么没有很多开发人员这样做呢? 主要的原因是时间不足。 我相信,最大的问题之一是我们的代码在层,类和具有外部框架的依赖关系之间耦合太深。 我想证明,创建框架的抽象层或将类解耦不是一件容易的事。 想象一下,我们需要开发一个应用程序,该应用程序需要知道用户的位置,因此,我们需要使用CoreLocation 。 我们的ViewController可能看起来像这样: https://gist.github.com/Juanpe/c4b0af6ac096a608e8737aba45c5345c 它有一个locationManager作为CLLocationManager ,以请求用户的位置或请求授权(如果适用)。 它还符合CLLocationManagerDelegate协议,并在其中接收locationManager输出。 在这里,我们可以看到ViewController与CoreLocation以及其他与职责分离相关的问题结合在一起。 无论如何,让我们为ViewController创建测试。 这可能是一个很好的例子: https://gist.github.com/Juanpe/0a332b315701dea350deab410db0c03d 我们可以看到sut ( 被测系统)和可能的测试之一。 在这里,我们请求用户的位置,并将其存储在我们的本地变量( userLocation )中。 这里的问题开始出现…… CLLocationManager管理请求,它不是一个同步过程,因此当我们检查存储的位置仍然为nil时 。 同样,我们可能没有授权请求位置的权限,在这种情况下,位置也将为nil 。 现在,我们有一些可能的解决方案! 让我们在不测试与位置相关的任何东西的情况下测试ViewController ,创建CLLocationManager的子类并模拟方法,或者尝试正确地进行操作并将CLLocationManager与我们的类分离。 我选了最后一个 “ Swift设计的核心是两个令人难以置信的强大想法:面向协议的编程和一流的值语义” – Apple POP是开发人员的强大工具,而Swift无疑是一种面向协议的语言。 所以我的建议是使用协议解决这些依赖性。 首先,要抽象CLLocation ,我们将定义仅包含代码所需变量或函数的协议。 https://gist.github.com/Juanpe/e71b220547eeda4318ef8b614a90f52f 现在,我们可以获得一个没有CoreLocation的位置。 因此,如果我们分析ViewController ,我们可以看到我们实际上并不需要CLLocationManager ,而只有在我们请求时向我们提供用户位置的人才可以。 因此,我们将创建一个包含我们需求的协议,只要符合该协议的人都可以作为提供者。 https://gist.github.com/Juanpe/ec84b3b26227d87f9759133914fb80b1 在我们的例子中,我们创建了UserLocationProvider。 该协议指定我们只需要一个方法来请求用户的位置,结果将通过我们提供的回调。 我们准备创建一个UserLocationService ,它符合该协议并向我们提供位置。 通过这种方式,我们已经在类中解决了CoreLocation的依赖关系,但是请稍候…… […]

编写可测试代码(iOS中的TDD示例)

在这个博客中,我将讨论编写可测​​试的代码,将解释我主要使用的两种方法,由您来决定最适合自己的方法。 我不是测试专家,这只是我高度使用的两种方法。 也许他们可以帮助您制定自己的首选方法。 这不是一个博客来告诉您您应该做什么和不应该做什么。 我鼓励您关心的唯一事情是将代码分开编写,使其易于阅读并遵循软件设计原则。 您可以在此处找到完整的模块。 meguid /可测试 这是我个人编写可测试代码的场所。 主要是TDD,设计可测试和重写的代码… github.com 我们需要编写一个简单的iOS模块,以帮助用户登录我们的系统。 我们将首先开始编写测试,然后再编写代码以通过此测试。 使用协议,我们可以将模块中的每一层完全分开,因此我们可以对其进行测试,而不必依赖于其他层。 对于我们的登录模块,我们将有两个核心层。 “交互者”的作用是控制模块逻辑,从模块外部(例如视图)采取措施,执行所需的逻辑,然后更新演示者。 “演示者”的作用是根据特定的逻辑来更新UI,演示者不应在意操作背后的业务逻辑。 另一个注意事项,将核心代码(演示者/交互者)与UI(仅导入Foundation)分开是至关重要的 让我们从一个快速的文件“ SignInProtocols”开始,该文件将负责管理层之间的交互,并且可以在解释模块具体功能方面发挥重要作用。 首先,我们需要定义我们的模块输入(也就是我们的模块要做什么)。 因此,我们使用3种方法来定义“ SignInInput”协议来登录和验证电子邮件,密码。 清楚吧? 那么,谁将成为我们的模块逻辑专家? 交互器。 因此我们需要将Interactor的输入定义为模块的输入。 因此,我们可以将登录模块输入操作委派给交互器。 现在我们需要定义Interactor输出。 是登录成功/失败还是电子邮件或密码有效。 目前很好? 那么谁来处理这个Interactor输出呢? 我们的UI大师。 主持人毫无疑问。 因此,像之前一样,我们将Presenter输入设置为Interactor输出。 现在,让我们定义演示者输出,在其中更新我们的UI。 最后,我们需要将模块设置为Presenter输出。 Interactor层将实现Interactor输入协议。 Presenter层将实现Presenter输入协议。 因此,现在我们定义了模块中的每个单元,我们甚至可以在定义各单元所需目的的层类(Interactor / Presenter)中编写一行代码之前轻松编写单元测试,以便我们可以编写测试。 我们编写模拟来创建一个伪图层,该伪图层实现我们的待测试层输出,以便我们可以验证我们的待测试层是否触发了正确的输出。 因此,在测试Interactor时,我们将模拟Interactor的输出协议,并在此输出中编写代码以配置标志,以便我们可以使用它来测试Interactor的行为是否 现在,我们准备测试Interactor的行为。 如果我们尚待编写的Interactor方法正确执行了此测试,则此测试将成功。 我们对Presenter也一样。 并测试一下。 我们做到了。 meguid /可测试 这是我个人编写可测试代码的场所。 主要是TDD,设计可测试和重写的代码… github.com 第一种方法使您能够分别测试每个层。 […]

通过单个单元测试取消Swift中的保留周期

不敢相信我们在2017年仍在处理这个问题吗? 好吧,这使我们两个人成为了现实。 尽管保留周期很容易修复,但是在关注代码库时也很难发现它们。 最近,我发现单个单元测试可以提供安慰。 仅需几行代码,它就可以在您进行更改时连续运行,同时还可以确保您没有引入任何新的内存泄漏。 这是一个简单的代码段,但我将带您逐步了解。 测试函数利用XCTest的异步期望系统来获取是否调用了类的deinit函数。 您需要的子类化技巧是必需的,因为Swift尚不支持反射。 子类通过添加deinitCalled闭包来跟踪deinit调用。 该测试通过在主队列上分配实例,同时立即在后台队列上分配实例来进行工作。 这将触发deinit调用,并且测试成功。 如果由于5秒超时而导致测试失败,这就是提示。 您刚刚发现了一个保留周期! 我发现在整个开发过程中运行此测试会有所帮助。 代码更改之间的差异仍然很小,足以使您忘记[weak self]或[unowned self] 。 PS我无法找到使测试功能通用的方法,因此我一直在复制粘贴它。 我意识到这并不理想。 但是,我发现这没什么大不了的,因为我们正在处理测试代码,而不是实际的应用程序代码。