iOS中的行为驱动开发
在编写单元测试时,开发人员通常由内而外地执行测试。 这意味着首先要编写对数据访问层的测试,然后是业务逻辑层,最后是用户界面层。
问题在于,我们离应用程序行为越远,我们与应用程序功能的隔离就越紧密。 行为驱动开发使我们可以从用户的角度而不是开发人员的角度来看应用程序。 在这篇文章中,我将使用行为驱动开发的原理来实现注册用户功能。
项目名称是“ People ”,它由一个单视图应用程序,一个单元测试项目和一个UI测试项目组成。 与其从数据库层开始,不如从我们要实现的功能/行为开始。 下面列出了一些功能:
- 作为用户,我应该能够成功注册一个帐户
- 作为用户,如果我使用现有的用户名,则应该收到错误消息
我坚信,如果您不进行测试优先开发,那么您将失去编写单元测试的许多好处。 TDD和BDD不仅允许您测试应用程序,而且还规定了应用程序的总体体系结构。
测试优先开发
甚至不用考虑在您的应用程序中编写一行代码! 我们将从编写单元测试开始。 我们将从编写UI测试开始,该测试将代表注册新用户的行为。
为了访问测试中的控件,您将需要使用可访问性标签提供一个标识符,如以下屏幕截图所示:
另外,请注意XCTest框架中没有tapAndType函数。 tapAndType函数是一种自定义扩展方法,它允许快速选择和设置UITextField的文本。
即使设置了标识符,测试仍将失败。 原因是我们尚未实现注册按钮事件的代码,并且尚未将用户带到登录屏幕。
此时,您将返回RegistrationTableViewController并实现按钮单击事件,如下所示:
由于您没有名为User的类或名为dataAccess的实例,因此这些代码均无效。 这将导致您实现User类,如下所示:
您还可以在iOS单元测试项目中编写单元测试,以确保可以创建User类的实例,如下所示:
我认为上述单元测试不会为我们实现所需功能提供任何价值。 单元测试仅仅是测试我们可以创建类的实例。
您应该始终编写单元测试来测试业务领域的复杂性,而不是语言功能。
这将引导我们进入数据访问层,我们将在下一节中介绍它。
资料存取层
为简单起见,我们将使用UserDefaults存储我们的数据。 我们将从实施单元测试开始,如下所示:
该测试甚至不会编译,因为我们的DataAccess类没有saveUser和getUsers函数。 让我们如下所示添加它们:
上面的代码进行了多次迭代和大量失败的单元测试。 即使现在,由于用户不符合NSCoding的要求,测试仍将失败。 让我们更新User类,使其符合NSCoding协议。
现在,如果您再次运行测试,则测试将通过,因为所有部分均已安装到位。 尽管数据访问测试可以通过,但最外部的测试仍将失败,因为注册后用户不会转移到“登录”屏幕。
塞格斯
在开始添加segue之前,请看一下之前实现的以下代码。
这是saveButtonClicked代码的最终版本。 原始实现如下所示:
如您所见,原始版本没有动态执行任何排序。 segue是使用Storyboard从按钮控件创建到LoginTableViewController的 。 这允许测试通过,但是后来我们转到下一个功能时测试被破坏了。
- 作为用户,如果我使用现有的用户名,则应该收到错误消息
现在,您将看到测试优先方法如何帮助我们设计了更好的应用程序。
打扫干净
单元测试最重要的原则之一是,它应该在完成状态后始终将其恢复为原始状态。 这意味着,如果您的单元测试将数据添加到数据库中,那么在测试结束时,它应该从数据库中删除数据。 这样可以确保在运行下一个测试时数据库处于初始状态。
UI测试中的一种技术是将参数从测试传递到可用于执行清除操作的应用程序。
该应用将在执行测试之前读取参数并清理资源。
观看下面的视频,该视频显示了正在运行的单元测试。
在业务领域复杂的大型应用程序中,单元测试变得非常重要。 尽管最初的单元测试将需要更多的时间来设置,但是随着项目的日趋成熟,它将分红。
您可以在此处下载完整的源代码。
如果您喜欢这篇文章并希望支持以后的文章,请按照下面的链接购买我的Udemy课程。
课程
编辑描述 www.azamsharp.com
谢谢您,祝您编程愉快!
Azam