uitest_UITest的提示和技巧

本文分享了关于uitest的一些提示和技巧,内容源于原文翻译:https://uxdesign.cc/tips-and-tricks-for-uitests-b3b81356b641,主要涉及该测试框架的使用心得。
摘要由CSDN通过智能技术生成

uitest

测试中 (TESTING)

This is the second article of a series on UITests. This article continues with the code prepared in the first one.

这是关于UITests系列的第二篇文章。 本文继续 第一个 代码中准备的代码

Let’s continue with what we started last week. In the previous article, we discussed how to setup UITests and how to assert the state of the UI to ensure that it’s behaving as we expect.

让我们继续上周开始的工作。 在上一篇文章中,我们讨论了如何设置UITest以及如何声明UI状态以确保其行为符合我们的预期。

We know that good tests must be:

我们知道好的测试必须是:

  • Independent from each other

    彼此独立
  • Repeatable

    可重复的
  • Must run as fast as possible.

    必须尽可能快地运行。

UITests make it hard to achieve these properties: in fact, a UITest runs in a separate process with respect to the app and it acts as a user that interacts with the app. Therefore, every time a UITest runs, it actually relaunches the app under test: if the app has saved something on the disk in the previous execution, then we will see those data in the current execution. Thus, the tests are not independent anymore, nor they are repeatable.

UITest使实现这些属性变得很困难:实际上,UITest在相对于应用程序的单独过程中运行,并且它充当与应用程序进行交互的用户。 因此,每次UITest运行时,它实际上都会重新启动被测试的应用程序:如果该应用程序在上一次执行中已将某些内容保存在磁盘上,那么我们将在当前执行中看到这些数据。 因此,测试不再是独立的也不可重复的

If the tests have to assert something into a very nested ViewController, the tests must perform a lot of navigation, thus they will run very slowly.

如果测试必须在非常嵌套的ViewController声明某些内容,则测试必须执行大量导航,因此它们将运行得非常

In this article, I’d like to share some tips and tricks that will make your tests more robust, more repeatable, cleaner, and faster. These tips and tricks leverage:

在本文中,我想分享一些技巧和窍门,这些技巧将使您的测试更强大,更可重复,更清洁,更快。 这些提示和技巧可以利用:

  1. Typed identifiers instead of raw strings to access the XCUIElements.

    输入标识符而不是原始字符串来访问XCUIElements

  2. Conditional compilation to exclude part of the code that makes sense only when running UITests and control the execution flow.

    条件编译可排除仅在运行UITest并控制执行流程时才有意义的部分代码。
  3. Launch arguments to pass some information to control the app behavior from the tests.

    启动参数以传递一些信息以控制测试中的应用行为。

Like last week, you can find the code here.

与上周一样,您可以在此处找到代码。

1.使用类型标识符 (1. Use Typed Identifiers)

In the previous article, we saw that it’s possible to use accessibilityIdentifiers to access to XCUIElements in a safe way, even when their static text change:

在上一篇文章中,我们看到可以使用accessibilityIdentifiers以安全的方式访问XCUIElement ,即使它们的静态文本发生了变化:

This certainly works. However, what happens if someone decides that the identifier convention must be changed? Or if she updates the "tos_button" to be something like "terms_of_services_button"?

当然可以。 但是,如果有人决定必须更改标识符约定,会发生什么? 或者,如果她将"tos_button"更新为类似于"terms_of_services_button"

In that case, the tests will break even if they shouldn’t. This approach is also very error-prone because who is writing the tests can always make a typo in one of the two places and such bugs are huge time sinks.

在这种情况下,即使不进行测试,测试也会失败。 这种方法也很容易出错,因为编写测试的人总是可以在两个地方之一中打错字,而这样的错误会占用大量的时间。

A more solid approach is to use enums, shared between the UITests target and the app target. In this way, we can define the identifiers only once and use them in two places.

一种更可靠的方法是使用在UITests目标和app目标之间共享的枚举。 这样,我们只能定义一次标识符,并在两个地方使用它们。

This can not be done just by importing the app module into the UITest one. That’s because those are two different targets which run in different processes. Xcode may build with the import, but it will crash at runtime because the UITests can not find the right identifiers. So, to make it work, we need to perform 2 steps:

仅仅通过将应用模块导入UITest并不能做到这一点。 这是因为这些是在不同流程中运行的两个不同目标。 Xcode可能会随导入一起生成,但由于UITests找不到正确的标识符,它会在运行时崩溃。 因此,要使其工作,我们需要执行两个步骤:

  1. Update the code with the new extension, where we define the enum.

    使用定义了enum的新扩展名更新代码。

  2. Add the file with the identifier to both targets.

    将带有标识符的文件添加到两个目标。

添加扩展 (Add the Extension)

To add the extension we can just refactor the old LegalView code, with this new code:

要添加扩展名,我们可以使用以下新代码重构旧的LegalView代码:

and then use the AccessibilityIdentifiers in the UITests:

然后在UITest中使用AccessibilityIdentifiers

If we build our code at this point, it will compile. But, as explained above, if we run it, it will fail badly. Let’s fix this crash.

如果我们此时构建代码,它将进行编译。 但是,如上所述,如果我们运行它,它将严重失败。 让我们修复此崩溃。

将查看文件添加到两个目标 (Add the View file to both targets)

To solve this issue, we have to add the files where the extensions are declared to both the targets. To do so we need to:

要解决此问题,我们必须将声明扩展名的文件添加到两个目标。 为此,我们需要:

  1. Open the right pane of Xcode

    打开Xcode的右窗格
  2. Open the File Inspector

    打开File Inspector

  3. Update the Target Membership of the LegalView file as the image shows.

    如图所示,更新LegalView文件的Target Membership

Image for post

By checking the last checkbox, we instruct Xcode to add the LegalView file to both the target. Now, our UITests have access to theAccessibilityIdentifiers!

通过选中最后一个复选框,我们指示Xcode将LegalView文件添加到两个目标中。 现在,我们的UITests可以访问AccessibilityIdentifiers

2.不提供UITest代码 (2. Do Not Ship UITest Code)

If your app supports Accessibility, fine. The code we wrote until now hits two pigeons with a single stone. However, chances are that you are not supporting it and, anyway, we will soon write some code in the app that makes sense only in the context of UITests. We don’t want that code to go in production.

如果您的应用程序支持Accessibility ,则很好。 到目前为止,我们编写的代码仅用一块石头就可以击中两只鸽子。 但是,很可能您不支持它,无论如何,我们很快就会在应用程序中编写一些仅在UITests上下文中才有意义的代码。 我们不希望该代码投入生产。

This can be easily done by using compilation pragmas. I think every one of you had written something like #if DEBUG <custom_code> #endif. The <custom_code> is something that the compiler builds and inject in the binary if and only if the DEBUG flag is set to 1.

这可以通过使用编译实用程序轻松完成。 我想你们每个人都写过#if DEBUG <custom_code> #endif<custom_code>是编译器将生成的东西, 并且仅当 DEBUG标志设置为1 ,才将其注入二进制文件。

So, let’s create a custom UITESTING flag that we can use to tell the compiler which portions of code make sense only in the context of UI testing. Do to so we need to:

因此,让我们创建一个自定义的UITESTING标志,我们可以使用该标志来告诉编译器哪些代码部分仅在UI测试的上下文中才有意义。 为此,我们需要:

  1. Create a new UITesting configuration;

    创建一个新的UITesting配置;

  2. Crete the new flags in both the UITesting target and in the App target;

    UITesting目标和App目标中UITesting新标志;

  3. Inform the compiler that we have to use them;

    通知编译器我们必须使用它们;
  4. Edit the scheme so that we use the new configuration when we run our tests;

    编辑方案,以便在运行测试时使用新配置;
  5. Use them in the code.

    在代码中使用它们。

创建一个新配置 (Create a New Configuration)

The first step is really easy.

第一步真的很容易。

  1. In the Project Navigator select the Root project, the one with the Xcode icon.

    Project Navigator选择Root项目,该项目带有Xcode图标。

  2. Select the Project and the Info tab

    选择ProjectInfo选项卡

  3. Under Configurations, press the + button and choose to duplicate the Debug configuration

    在“ Configurations ,按+按钮,然后选择复制“ Debug配置

  4. Insert the UITesting as name.

    插入UITesting作为名称。

Image for post

创建UITesting标志并激活它们。 (Create the UITesting Flags and Activate Them.)

We need to create the flags we are going to use and we have to activate them. Luckily, we are already in the right window of Xcode, so we can just follow these steps:

我们需要创建将要使用的标志,并且必须激活它们。 幸运的是,我们已经在Xcode的右侧窗口中,因此我们可以按照以下步骤操作:

  1. Click on your App Target (UITesting in the example).

    单击您的App目标(在示例中为UITesting )。

  2. Select the Build Settings tab.

    选择Build Settings选项卡。

  3. Filter for Preprocessor Macros.

    Preprocessor Macros过滤器。

  4. Add the UITESTING=1 flag for the UITesting configuration.

    UITesting配置添加UITESTING=1标志。

  5. Filter for Active Compilation Conditions.

    Active Compilation Conditions过滤器。

  6. Add the UITESTING flag in the UITesting configuration. This activates the flag when the app is running in that configuration.

    UITesting配置中添加UITESTING标志。 当应用程序在该配置中运行时,这将激活该标志。

  7. Repeat the steps 1 to 6 for the UITest Target (UITestingUITest in the example).

    UITest目标( UITestingUITest中的UITestingUITest )重复步骤1至6。

At the end of the steps, if you filter for DEBUG in one of the two targets we modified, you should have a situation similar to this one.

在步骤的最后,如果您在我们修改的两个目标之一中过滤DEBUG ,那么您应该会遇到与此类似的情况。

Image for post
The UITESTING flag is set to true for the UITesting Target and Swift knows that the flag is enabled when we run the code with the UITesting configuration.
UITesting目标的UITESTING标志设置为true,当我们使用UITesting配置运行代码时,Swift知道该标志已启用。

更新方案以使用新配置 (Update the Scheme To Use the New Configuration)

At this point, we need to update the scheme to inform Xcode that we want to use the new configuration when we run the tests. To do so we need to:

此时,我们需要更新方案,以在运行测试时通知Xcode我们要使用新配置。 为此,我们需要:

  1. Click on the App next to the Play and Stop buttons in Xcode

    单击Xco​​de中“ Play和“ Stop按钮旁边的App

  2. Select Edit Scheme

    选择Edit Scheme

  3. Click on Test

    点击Test

  4. Select the UITesting configuration

    选择UITesting配置

Image for post

From now on, whenever we press cmd+U we are going to use the UITesting configuration which is aware of the new UITESTING compiler flag. Now we just need to…

从现在开始,每当我们按cmd+U我们将使用UITesting配置,该配置知道新的UITESTING编译器标志。 现在我们只需要...

使用标记中的代码 (Use the Flag In Code)

To use it, we leverage the same syntax of #if DEBUG <custom_code> #endif. We need to navigate to the LegalView file and update the code as follows:

要使用它,我们利用与#if DEBUG <custom_code> #endif相同的语法。 我们需要导航到LegalView文件并更新代码,如下所示:

With this code, everything that is between #if UITESTING and #endif is not included in the binary unless the UITESTING flag is set to 1 and that’s true only when we run UITests.

使用此代码,除非UITESTING标志设置为1 ,否则#if UITESTING#endif之间的所有内容都不会包含在二进制文件中,并且仅当我们运行UITests时才如此。

3.使UITest与应用程序通信 (3. Make UITest Communicates With the App)

As already stated above, UITests run in a different process with respect to the app they interact with. So… how can we control the state of the app so that our tests are predictable and repeatable?

如上所述,UITest在与之交互的应用程序上以不同的过程运行。 那么……我们如何控制应用程序的状态,以便我们的测试是可预测的和可重复的?

XCUIApplication allow us to pass some launch arguments from the UITest to the application. Once those arguments are received by the app, we can then handle them appropriately. To do so we need to:

XCUIApplication允许我们将一些启动参数从UITest传递到应用程序。 应用收到这些参数后,我们就可以对其进行适当处理。 为此,我们需要:

  1. Set the arguments we need before calling XCUIApplication.launch

    在调用XCUIApplication.launch之前设置我们需要的参数

  2. Parse the arguments in the app.

    解析应用程序中的参数。
  3. Implement the logic to react to these arguments.

    实现对这些参数做出React的逻辑。

To illustrate this process, consider that we want to create a test that starts the app directly in the HomeView instead of launching it from LegalView and then navigate to the HomeView.

为了说明此过程,请考虑我们要创建一个直接在HomeView中启动该应用程序的测试,而不是从LegalView中启动它,然后导航至HomeView

传递启动参数 (Pass Launch Arguments)

To pass launch arguments, simply set them in the app before invoking the launch method.

要传递启动参数,只需在调用启动方法之前在app进行设置即可。

解析应用程序中的参数并处理代码 (Parse the Arguments in the App and Handle the Code)

Now, we need to parse them. If you ever wrote a CLI program, you know how tedious this code can be. Instead, I’d like to thank John Sundell for this nice little trick: we can use UserDefaults to parse the arguments, leveraging also the Swift type system!

现在,我们需要解析它们。 如果您曾经编写过CLI程序,您就会知道此代码可能很繁琐。 相反,我要感谢John Sundell这个小技巧:我们可以使用UserDefaults来解析参数,还可以利用Swift类型系统!

In this code, you can see a couple of things:

在这段代码中,您可以看到几件事:

  1. we keep our functions small and simple. The scene(_:willConnectTo:options:) calls a function called buildViewController() that perform the #if UITESTING check and creates the right UIViewController based on the argument.

    我们保持功能小而简单。 scene(_:willConnectTo:options:)调用一个名为buildViewController()的函数,该函数执行#if UITESTING检查并根据该参数创建正确的UIViewController

  2. In the app, we access the launch argument without using the - symbol. That symbol is a convention that tells UserDefaults that what follows the - is the key and the next argument is the value for that key. In fact, when we access the UserDefaults.standard.string(forKey: "initialScreen") UserDefaults returns the "home_view" value.

    在应用程序中,我们无需使用-符号即可访问启动参数。 这符号是告诉约定UserDefaults什么如下-key ,下一个参数是该键的值。 实际上,当我们访问UserDefaults.standard.string(forKey: "initialScreen") UserDefaults返回"home_view"值。

The code to handle the launch argument is pretty simple: we just have to switch on the argument value to present the right UIViewController.

处理启动参数的代码非常简单:我们只需要打开参数值即可显示正确的UIViewController

Today we explored some more advanced topics in the field of UITests. We learn how to structure our code to be more robust, how we can avoid to compile and push in production testing code, and we learn how the UITests and the app can communicate.

今天,我们探讨了UITests领域中的一些更高级的主题。 我们将学习如何使代码结构更健壮,如何避免编译和推送生产测试代码,以及UITests和应用程序如何进行通信。

There are still some more topics about UITests that I like to discuss: how can we pass complex information to the app, how to clean the state so that the tests can be independent, how to mock dependencies so that the tests are reliable.

我还想讨论有关UITest的更多主题:如何将复杂信息传递给应用程序,如何清除状态以使测试可以独立,如何模拟依赖项以使测试可靠。

However, I’d like to keep these topics for the next week: I think that there is enough information to assimilate in today’s article.

但是,我想在下周保留这些主题:我认为今天的文章中有足够的信息可以吸收。

Image for post
Bay Area Black Designers: a professional development community for Black people who are digital designers and researchers in the San Francisco Bay Area. Being designers from an underestimated group, BABD members know what it feels like to be “the only one” on their design teams. By joining together in community, members share inspiration, connection, peer mentorship, professional development, resources, feedback, support, and resilience. Silence against systemic racism is not an option. Build the design community you believe in. 海湾地区黑人设计师 :一个专业的黑人开发社区,他们是旧金山湾区的数字设计师和研究人员。 作为来自一个被低估的团队的设计师,BABD的成员知道成为设计团队中“唯一的一个”的感觉。 通过在社区中团结起来,成员可以共享灵感,联系,同伴指导,专业发展,资源,反馈,支持和韧性。 对系统性种族主义保持沉默是不可行的。 建立您相信的设计社区。

翻译自: https://uxdesign.cc/tips-and-tricks-for-uitests-b3b81356b641

uitest

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值