Tag: 单元测试

重构和测试旧版代码

在创建单元测试时,我们所有人都会时不时地挣扎,主要是当MainView依赖于核心/服务类(网络服务,API服务等)时。 有一些设计模式可以帮助我们避免这种情况,但是老实说,并非每次都可行,主要是在处理遗留代码时。 因此,这里有一个易于实施的好“技巧”,可以帮助您进行测试,而无需进行任何重大的重构。 MVVM和面向协议的编程在这里可以帮助我们进行依赖注入。 将这两者结合在一起,将使我们能够创建一个符合您所有ViewModel依赖项的存根类。 我们将其称为ServiceStub 。 此类将符合我们所有的依赖协议,并将负责在运行测试时为ViewModel提供所需的信息。 听起来很不错,但我们应该开始使用一些代码来了解发生了什么。 XCode 9.2以上 斯威夫特4 熟悉Model-View-ViewModel(MVVM)模式 对Nimble或XCTest有所了解 对如何编写单元测试的基本了解 椰子足 代码 要开始使用代码,请转到此处并克隆或下载示例代码,运行pod install并打开工作区。 现在好了,我们准备开始。 该示例代码提供了两个服务类( LocationService和ApiClient )和一个MainView 。 到目前为止,对服务类的每次调用都在视图控制器上进行。 让我们通过重构视图模型的所有LocationService和ApiClient调用来更改此设置。 我们的第一步将是创建视图模型并重构我们的MainView然后测试视图模型上的所有公共功能。 首先,让我们运行该应用程序。 它使用GitHub API和用户位置来获取iOS开发人员的可用职位,但是用户可以通过键入邮政编码来更改搜索的位置。 每次用户输入新的邮政编码并进行搜索时,地址标签都会更改,并进行呼叫以获取iOS职位。 初始点 让我们创建视图模型。 为此,在“单元测试依赖项教程”内的项目导航器上单击鼠标右键,选择“新建组”并将其命名为“ ViewModels”。 现在在新创建的文件夹中使用command + N ,选择一个Swift File并将其命名为MainViewModel 。 确保在组区域下方选择两个目标。 (应用和测试目标) 现在,您的文件夹结构应如下所示。 现在,让我们移动func updateCurrentAddress()和 从MainView到MainViewModel func fetchJobsAround(postalCode: String)方法,并删除与视图控制器相关的所有代码。 添加以下代码: 我们将使用变量addressCompletion将地址传回视图控制器,并将作业结果与函数中的完成块一起addressCompletion 。 有更好的方法将数据传递回视图控制器(反应式方法,通知,委托等),但是出于本教程的考虑,我们的方法可以正常工作。 到现在为止,您的项目应该可以正常构建,以确认command […]

iOS中的真实场景单元测试

在敏捷开发环境中,编写单元测试和测试驱动的开发是团队和开发人员最后考虑的事情。 编写单元测试浪费时间,维护麻烦并且会污染生产代码是一个神话。 相反,它使您可以遵循最佳实践,例如依赖项注入,松散耦合的代码,编写自Swift发行以来受到广泛认可的协议。 单元测试对于避免大型团队的项目中的错误非常有帮助,因为新的开发人员加入团队可以进行一些更改,这些更改可能会使某些测试用例和方案失败,因此,如果编写了测试用例,则可以很早地发现它。 它还有助于在编写逻辑或函数时考虑所有可能出现的情况。 单元测试的网络示例: 如果您的测试目标(SUT,被测系统)以某种方式与现实世界相关,例如网络和CoreData,则编写测试代码会更加复杂。 基本上,我们不希望我们的测试代码依赖于现实世界中的事物。 SUT不应依赖于其他复杂系统,因此我们能够更快,时间不变和环境不变地对其进行测试。 此外,重要的是我们的测试代码不要“污染”生产环境。 “污染”是什么意思? 这意味着我们的测试代码将一些测试内容写入数据库,将一些测试数据提交至生产服务器,等等。这就是存在依赖项注入的原因。 给定一个应该在生产环境中通过Internet执行的类。 Internet部分称为该类的依赖项。 如上所述,当我们运行测试时,该类的Internet部分必须能够用模拟或伪造环境代替。 换句话说,该类的依赖关系必须是“可注入的”。 依赖注入使我们的系统更加灵活。 我们可以在生产代码中“注入”真实的网络环境。 同时,我们还可以“注入”模拟网络环境来运行测试代码,而无需访问互联网。 为URLSession创建协议,以便可以将模拟对象注入到HttpClient中。 协议1:URLSessionProtocol提供dataTask api。 协议2:URLSessionDataTaskProtocol提供恢复API。 因此,如您在上面的屏幕截图中所见,测试用例已失败。 XCTAssertNotNil的执行无需等待get API的结果。 幸运的是,我们有XCTest Expectations可以测试异步代码。 该机制允许您指定一个或多个“期望”,这些期望将由于测试中的操作而异步发生 。 一旦设置了所有期望值,就会调用“等待” API,该API将阻止后续测试代码的执行,直到满足所有期望条件或发生超时为止。 运作方式: 设置一个“期望”,告诉Xcode它应该开始等待。 当我们的异步代码返回时,我们通知测试运行器一切正常,不再需要等待。 让Xcode知道失败之前应该等待多长时间。 因此,通过定义期望并在接收到数据时调用满载api(),并通过调用API waitForExpectations并设置计时器,直到Xcode必须等待期望完成,才使Xcode在XCTAssert调用之前等待。

Swift 3.0 ile Unit Testi

Herhangi bir kod yazmayabaşlamadanönce,单元测试中心,neden yapmayadeğerolduğunu已成功地完成了所有任务。 单元测试,测试小组,测试小组成员,测试小组成员,测试小组成员,测试小组成员。 Bu,işlevlerimizinbeklendiğigibiçalıştığınıdoğrulamaolanağısağlar。 雅妮,herhangi井işlevICIN已经井笛子girdiverildiğinde,işlevindoğrudeğerleridöndürüpdönmediğinibelirleyebiliriz已经geçersizgirdisağlanırsayürütmeişlemisırasındabaşarısızlıkları扎里夫井şekildeişleyebiliriz.Sonuçta,BU belirli井işlevioluşturankodun kalitesiniartırmayayardımcıolmak ICINalgoritmalarımızdakiveyamantığımızdakihatalarıbelirlememizeyardımcı oluyor。 XCode 8.1’de swift ilenasıl单元测试一般可用于单元测试。 单元测试示例包含单元测试,包括单元测试。 Projemizioluşturduktan桑德拉testiniyazacağımızfonksiyoniçinbasit bir senaryogeliştirelim。 Kullanıcımızdan名称ve agedeğişkeniolan iki tane用户nesnesialalımvebunlarınyaşıküçükolanınadınıdönenuygulamayıyapalım。 使用olarak用户模型。 使用者必须先进行操作,然后再进行操作。 达哈·索纳·埃克兰丹(danha sonra ekrandan)和其他用户之间的比较。 Buraya kadar kikısımbasit bir fonksiyon yazmakiçindi。 测试sınıflarıoluşturmayabakmadanönce,测试gezgini birgözatmayadeğer。 测试gezgini,projeiçindekitüm测试paketlerinin kaynak kodbileşenlerinibelirler ve测试sınıflarınıve测试yöntemlerinihiyerarşikbir已列出görüntüler。 Şimdibuyazdığımızfonksiyonun testiniyazalım。 UnitTestExampleTests可以设置,删除并测试fonksiyonu olan testExample的设置,还可以进行拆解。 设置fonksiyonu kurulum kodyazılankısımdır。 Buyöntem,sınıftaki她的测试yöntemininçağrılmasındanönceçağrılır。 tearDown isesınıftaki她的测试yöntemininçağrılmasından桑拉çağrılır。 Fonksiyonumuzu测试工具已设置,但用户已安装了该工具。 Daha声呐testCompareUserAgeadındabir test […]

iOS中的测试驱动开发,SWIFT 4-第1部分

测试驱动开发(TDD),一种敏捷的软件开发方法,通过为我们的业务逻辑单元编写测试用例,可以使开发过程更无错误,并使代码更稳定。 如果您是TDD的新手,并且想稍微进一点,那么您想查看一下我先前关于测试驱动开发(TDD)的博客。 在iOS中,Xcode使单元测试比任何其他现代编程工具都容易得多。 让我们立即跳入编码,开始我们的冒险。 我们将使用MVVM构建我们的项目,因为它更易于进行基于组件的测试,因为我们对测试我们的业务逻辑而非控制器更感兴趣。 如果您不熟悉MVVM,那么您想快速浏览一下我关于MVVM的博客系列。 我们将学到什么? 我们将不仅致力于学习如何使用Xcode在iOS中编写测试用例,还将关注如何思考和计划我们的测试用例。 在Xcode项目中启用UnitTestCase 在新项目中启用。 添加现有项目。 ->要在现有项目中添加单元测试用例,我们需要添加一个新的iOS Unit Testing Bundle目标。 我们要建造什么? 我们将构建一个示例应用程序,该应用程序将获取场所(如商业场所和商业场所)的列表并显示它们。 因为我希望此博客非常简单,所以将从.json文件中获取位置列表。 让我们检查将用于DemoTests项目的UML类图。 下载 用于初始项目设置 的 启动程序项目, 即UT_Starter1。 入门项目具有上述屏幕的view , view模型和相应的测试文件。 作为#Rule1,我们需要编写有关Red-> Green-> Refactor流程的测试用例。 由于我们已经准备好编写测试用例,因此在Xcode中创建任何单元测试类时,都会生成一些自动生成的方法。 让我们继续学习该类中列出的所有方法: func setUp() 这是我们得到的最简单的Red案例。 因此,任何错误,即使是“未解决的标识符”也被视为红色案例。 绿色: 我们将编写最简单的代码来通过我们的测试用例。 导航到Place.swift 。 将以下代码放置在文件中。 在@testable import DemoTests下面写下@testable import DemoTests PlaceTests.swift 。 现在再次运行。 有用!! 您将在文件中看到绿色的勾号。 这意味着我们的代码已通过测试用例。 因此,我们已经成功地写下了绿色代码。 重构: 到目前为止,代码中没有太多可重构的,我们可以跳过这一部分。 […]

使用Swift在iOS上进行单元测试Model View Controller

Swift Single App View项目设置 因此,这很简单,只需打开Xcode,单击“创建新的Xcode项目”,选择“ iOS”和“ Single View App”。 然后单击“下一步”。 我将我的项目命名为“ Account”,但是您可以随便调用它。 从下拉框中选择适当的团队。 然后,取消选中“包括UI测试”和“使用核心数据”。 我们对单元测试感兴趣,因此请选中“包括单元测试” 。 然后,单击“下一步”。 至此,我们有了可以开始构建的样板代码。 让我们花点时间注意Xcode为我们创建的所有文件。 其中包括AppDelegate,主故事板,“帐户组”文件夹下的ViewController和具有一些样板单元测试用例的AccountTests文件。 我们的ViewController具有以下代码: 我们已经完成了在应用程序中实现整个MVC模式的工作,并为此编写了单元测试。 最后,我希望您在尝试开发MVC应用程序时记住以下几条原则 使用协议在控制器中建模和查看 对模型和视图使用合成而不是继承。 对控制器的模型和视图使用依赖注入 。 并始终尽早编写单元测试用例 。 希望本文能有所帮助,因为这是我的第一篇有关媒体的文章,请让我知道我的工作方式。 我在Orthogonal工作,我们根据监管准则和标准为客户开发医疗应用程序。 由于这些应用程序与健康相关,因此我们遇到了非常新颖和前沿的概念,这些概念处于AI,IoT和医学的交汇处,我们与客户合作进一步发展。 听起来很有趣? 我们一直在寻找有才能的人。 在https://orthogonal.io上查看我们

如何编写核心数据的单元测试用例

在本教程中,您将了解如何在Xcode中构造Core Data Stack来测试您的Core Data应用程序。 这并不是应该的那么简单,因为大多数测试将取决于有效的核心数据堆栈。 您不想破坏单元测试中的数据,以免干扰您自己在模拟器或设备上进行的手动测试。 访问控制 默认情况下,swift中的类具有“内部”访问级别。 这意味着您只能从它们自己的模块中访问它们。 由于应用程序和测试位于单独的模块中,因此您将无法在测试中从应用程序访问类。 如何解决这个问题 1.)您可以将应用程序中的类和方法标记为公共,以使其在测试中可见。 2)您可以在单元测试中的任何导入前面添加Swift关键字@testable,以访问该类中导入的所有内容。 @testable导入CoreDataUnitTesting 添加@testable是执行此操作的更好方法,因为您不必将您的类和方法标记为公开以进行测试。 您应用中的核心数据栈将像这样:: 类CoreDataStack { public init(){ } 懒惰的varpersistentContainer:NSPersistentContainer = { 让容器= NSPersistentContainer( 名称:“ CoreDataUnitTesting”) container.loadPersistentStores( completeHandler:{中的(storeDescription,错误) 如果让error = error as NSError? { fatalError(“未解决的错误\(错误), \(error.userInfo)“) } }) 返回容器 }() var applicationDocumentsDirectory:NSURL = { 让urls = FileManager.default.urls(用于: .documentDirectory,位于:.userDomainMask) 返回urls [urls.count-1]作为NSURL }() 公开varmanagedObjectModel:NSManagedObjectModel = […]

iOS单元测试简介

您最有可能阅读本文,因为您已经听说过有关单元测试的知识,并且想要了解更多。 如果您从未听说过单元测试,并且想要基本介绍,那么您来对地方了。 本文将为您提供单元测试的一般概述,并将讨论单元测试与iOS之间的关系。 什么 如果您考虑一下, 每个复杂的系统都由较小的部分组成。 您的汽车配有发动机,燃油管,油箱,挡风玻璃等。 将这些组件中的每一个组合在一起,就可以构成您的汽车。 您的汽车行驶到任何地方的唯一原因是这些组件中的每个组件都能发挥出色的作用。 单元测试中的“单元”是这些组件之一。 单元测试不仅适用于软件。 它是一个广义的工程术语,可以应用于由零件组成的任何领域,每个领域都需要完成特定的工作。 您可以将汽车拆开并在每个组件上运行诊断程序,以对汽车进行单元测试。 也许您想测试机油滤清器清除某些脏油的能力,或者您想测试气帽上的密封。 每个测试都是一项测试,您可以对组成汽车的各个单元进行测试。 这很有趣。 我已经看到“单元测试”一词在某些我从未期望使用过的领域中得到了应用。 在星际争霸中。 如您所见,这是一个非常广泛的概念。 编写有效的单元测试需要什么 一个好的单元测试需要具备以下条件。 您正在测试的隔离组件。 如果您一起测试一件事以上,那就是集成测试 。 您正在测试的特定行为。 不用说,此行为需要与您正在测试的组件有关。 成功和失败的条件。 毫无疑问。 在单元测试中,没有什么是部分成功的 。 运行时,每个单元测试必须成功或失败。 这些看起来很简单,但是您通常会发现第一部分具有挑战性。 大多数系统并不是以模块化的方式设计的,因此需要花费一些额外的精力才能有效地隔离不同的组件。 挑战:隔离组件 例如,假设您要在汽车的机油滤清器上进行单元测试。 您不能只是弹出过滤器并对其进行测试。 您必须将其卸下,将机油排入锅中,进行测试,将其放回去,然后再将油放回车中。 如此彻底地测试机油滤清器需要花费大量时间和精力,这就是为什么大多数机油滤清器都是一次性产品。 您只需在一定距离后或在怀疑它们会变坏时更换它们。 他们就像灯泡。 花时间尝试修复它们是浪费。 汽车中几乎每个组件都很难进行单元测试。 您几乎永远都不会在该级别上测试汽车的组件。 实际上,您在汽车上进行的大多数测试都是集成测试。 整合测试 集成测试是将一个或多个组件一起测试的任何测试。 当您测试汽车将清洗液输送到挡风玻璃的能力时,您正在执行集成测试。 您可以同时测试清洗液泵,清洗液管线和喷涂机机构。 除非有严重的故障,否则任何理智的人都不会花费时间或精力单独测试这些组件。 将系统分解并重新组合在一起会花费太多时间。 这个类比并没有完全映射到软件领域,但是有一个重要的考虑因素。 设计这样一个易于分解的系统需要花费额外的精力。 无论是汽车,软件还是星际争霸战,您都需要考虑这一成本。 大多数汽车都不容易进行单元测试,因为单元测试不是其设计的核心。 汽车公司不希望您一直保持汽车所有零件的良好维护。 […]

什么是@testable?

在编写代码时,我们根据类和方法的使用情况定义它们的访问级别。 在编写测试时,我们必须在测试目标中访问这些类和方法。 如果我们未指定显式访问级别,则代码中几乎所有实体都具有默认的内部访问级别。 结果,在许多情况下,我们不需要在代码中指定显式访问级别。 swift的访问控制模型可防止外部实体访问在应用程序或框架中声明为内部的任何内容。 默认情况下,为了能够从我们的测试代码访问这些项目,我们需要将它们的访问级别至少提高到公共级别,从而降低快速类型安全的好处。 解: 1.启用“可测试性”构建设置为“是”。 Xcode在编译过程中包含-enable-testing标志。 这使得在编译模块中声明的快速实体有资格获得更高级别的访问权限。 2.当我们将@testable属性添加到已启用测试的模块的import语句中时,我们将在该范围内激活该模块的提升的访问权限。 标记为“公开”的班级和班级成员的行为就像标记为“公开”一样。 其他标记为内部实体的实体就像被宣布为公共实体一样。 注意: 我们无论如何都不会更改源代码。 我们仅修改编译(通过设置标志)。 和测试代码(通过修改import语句)。 @testable仅提供对内部函数的访问; 使用可测试时,fileprivate和private声明在其通常范围之外不可见。 感谢您的阅读 🎾

开始进行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)被广泛地用于教会新开发人员如何进行编码。 […]

教程:如何在iOS应用中对私有方法进行单元测试

在之前的文章中,我提到了一种为私有方法编写单元测试的方法。 你们中的许多人对此可能性感兴趣,并想了解更多。 我认为这将有助于为您提供一个可以遵循的教程,因此请继续。 如果您回想起上一篇文章,我说过微框架是解决此问题的一种方法。 什么是微框架? 没什么特别的,只是导入到主应用程序目标中的一个小框架。 为什么这样做 任何具有内部访问级别的内容都可以在其测试模块的单元测试目标中访问。 然后,将相同的框架导入到主应用程序目标后, 内部实体将无法访问,或者出于所有实际目的变为私有。 如果所有这些听起来像胡言乱语,请不要担心。 让我们通过一个小教程逐步完成它。 入门 继续并从Github获取入门项目。 这里没有什么特别的事情,它只是一个空的单视图应用程序。 由于这是一个有关微框架的教程,因此,我们转到File-> New-> Target来创建一个新框架。 框架是一种目标。 它是一个代码模块,可以导入到另一个标记中,例如您的主应用程序的目标。 停留在iOS上,并一直向下滚动。 选择“ Cocoa Touch Framework”,然后单击下一步。 您将被带到另一个屏幕,您可以在其中命名您的自定义框架。 遵循Apple的命名约定,我选择将其命名为CoreTrick。 选中包含单元测试复选框非常重要。 这就是让您为要导入的框架编写单元测试的原因。 单击“完成”,然后在您的项目上单击以再次检查一切是否正常。 如果遵循正确,您将看到一个应用程序目标,一个应用程序目标的单元测试目标,一个框架目标以及该框架目标的另一个单元测试目标。 TrickTrackerTests是TrickTracker的单元测试目标,TrickTracker是主要的应用程序目标。 CoreTrickTests是CoreTrick的单元测试目标,CoreTrick是框架目标,它将包含您要测试的所有实体。 大! 您已经准备好开始编写一些代码。 让我们创建一些内部实体并对其进行测试 通过内部 , 我只是指与他们相关的访问级别。 函数,变量,类,枚举和结构都可以标记为internal 。 这仅表示这些实体只能在定义它们的模块内访问。 在这种情况下,那就是CoreTrick框架。 我确定您还熟悉其他访问级别。 Public表示可以在模块外部访问实体。 打开意味着它可以在模块外部访问,并且可以被子类覆盖。 私有意味着只能在实体本身的范围内访问它。 单板滑雪特技动作实体 我们的Snowboard Trick Tracker应用程序可跟踪您的滑雪技巧(phe们说快了五倍!)。 它使用具有一些基本属性的简单Snowboard Jump Trick实体。 创建一个名为SnowboardJumpTrick的新Swift文件,并将以下代码粘贴到其中。 […]