UI测试时模拟网络通话

为了对应用程序进行UI测试,我正在研究在测试执行期间模拟所有网络调用的最佳方法。

模拟网络调用的动机是消除执行测试时的不确定性。 我们不能依靠服务器来运行,我们的测试用例所基于的数据总是一样,等等。此外,模拟所有调用将使测试运行更快。

UI测试的问题是Apple对其进行设置的方式,使您的应用在一个过程中运行,而在另一个过程中进行测试。 UI测试使用UIKit内置的可访问性功能与在单独进程中运行的应用程序进行交互。 随之而来的问题是,我们不能像通常在单元测试中那样注入模拟或存根网络调用。

根据我的阅读,有两种方法可以解决此限制。

一方面,我们可以将我们需要的所有固定装置(我们将用作响应模拟调用的文件,它们可以是json,xml等)放置在应用程序的主要目标中,并提供模拟框架以及在运行UI测试时通过环境变量,以告知我们的应用设置模拟程序。

这种方法让我有些困扰。 首先,我们仅将特殊代码用于运行测试,应尽可能避免这种做法。 这看起来从不漂亮,可能导致错误,使代码的可读性和可维护性降低。

另一个选择是在本地运行服务器,该服务器嵌入执行测试的过程中,在该过程中,我们对网络调用进行存根(stub),测试正在命中并返回固定装置。

Michal Ciurus的一则帖子详细介绍了他的操作方式。 在他的情况下,在应用程序进程中进行存根对他来说不是一个选择,因为他需要动态更改服务器的响应。 他使用swifter作为服务器,这是用Swift written编写的简约HTTP服务器。 还有其他使用其他服务器的帖子,例如Fang-Pen Lin的帖子。

Michal分享了我们需要设置服务器和对电话进行存根的类:

帮助程序类,以建立快速和存根我们的电话

然后我们简单地像这样使用它:

我们可以在helper类中设置常量存根,或者根据需要在测试中动态设置新的存根,如上面所示。

现在唯一需要做的就是告诉我们的应用使用http://localhost:8080作为调用的端点。 我有两个xconfig文件,即Debug和Release,用于设置测试和生产端点。 我使用http://localhost:8080作为端点创建了另一个UITesting。 将UITesting的特定xconfig 设置为UI Testing方案的Test ActionBuild Configuration

现在,我们的道路上仅有一个最后的障碍,即应用程序传输安全性(ATS)。 在iOS 9中引入了Apple激励开发人员使用基于HTTPS的安全网络连接来提高用户安全性和隐私性。 但是swifter仅通过HTTP起作用。 有一种方法可以在我们的Info.plist添加异常,但是Apple建议它是临时的,从而提示开发人员确保他们在其应用程序中使用的资源的安全。 自2017年以来,除了开发人员可以证明其合理性的情况之外,Apple拒绝使用此异常的应用程序。

有一种方法可以使用密钥NSAllowsLocalNetworkinglocalhost添加一个不需要理由的异常,但只能在iOS 10上使用NSAllowsArbitraryLoads可以在iOS 9中使用

NSAllowsLocalNetworking should be added to the plist with iOS 10. Source.

就我而言,因为我使用iOS 10运行测试,所以只需要NSAllowsLocalNetworking 。 这样,我们的测试将可以正常调用http://localhost:8080 ,并且应用程序将使用我们存根的响应。

这种方法的优点是非常易于设置和维护,服务器直接从我们的代码启动,并且我们不必在应用程序中放置任何测试代码。