简体   繁体   English

构建XCTest UI测试套件的最佳实践是什么?

[英]What are the best practices for structuring an XCTest UI Test Suite?

I am setting up a test suite for an iOS app. 我正在为iOS应用程序设置测试套件。 I am using Xcode's XCTest framework. 我正在使用Xcode的XCTest框架。 This is just a UI test suite. 这只是一个UI测试套件。 Right now I have a test target with one file TestAppUITests. 现在我有一个测试目标有一个文件TestAppUITests。 All of my test cases reside in this file (first question: should all of my test cases be in here or do I need more files?) Within this file, I have a bunch of test cases that work as if it's a user using the app. 我的所有测试用例都驻留在这个文件中(第一个问题:我的所有测试用例都应该在这里,还是我需要更多的文件?)在这个文件中,我有一堆测试用例就好像是用户使用的一样应用程序。 Logging in/ Create account then login -> Navigate around app -> Check if UI elements loaded -> Add additional security like secondary email address -> logout. 登录/创建帐户然后登录 - >浏览应用程序 - >检查是否加载了UI元素 - >添加其他安全性,如辅助电子邮件地址 - >注销。 How should these be ordered? 这些如何订购?

I've researched all around, found some gems here and there but still have questions. 我到处研究过,在这里和那里发现了一些宝石,但仍有疑问。 Within the test target, should you have multiple files? 在测试目标中,您应该有多个文件吗? I just have the one within my UITest target. 我只是在我的UITest目标中有一个。 My other big question is a bit harder to explain. 我的另一个重要问题是难以解释。 Each time we run the test suite from the beginning the app starts in a state where you are not logged in, so, for example, in order to test something like navigate WITHIN the app, I need to run that test to login first. 每次我们从一开始就运行测试套件时,应用程序就会在您未登录的状态下启动,因此,例如,为了测试类似于在应用程序中导航的内容,我需要运行该测试以首先登录。 Right now I have it setup so that the login test runs once, then all other tests after it, then ends with logout. 现在我设置它以便登录测试运行一次,然后是其后的所有其他测试,然后以logout结束。 But that one file TestAppUITests is getting very long with tons of test cases. 但是,一个文件TestAppUITests变得非常长,有大量的测试用例。 Is this best practice? 这是最佳做法吗?

Soo. 洙。 Lets divide this into more parts: 让我们把它分成更多的部分:

1/ Should all of my test cases be in here or do I need more files? 1 / Should all of my test cases be in here or do I need more files?

Well - your tests are same as any other app code, you have. 好吧 - 您的测试与任何其他应用程序代码相同。 Do you have all of the app code in one file? 你有一个文件中的所有应用程序代码? Probably not, so a good practice is to divide your tests into more classes (I do it in the way of what they test - LoginTests class, UserProfileTests class etc etc.). 可能不是,所以一个好的做法是将测试划分为更多的类(我按照他们测试的方式进行 - LoginTests类, UserProfileTests类等等)。

To go further with this - I have test classes and methods divided into separate files - fe I have a method, that will do a login in UI test, so I have the method in UITestCase+Login extension ( UITestCase is a class, that is extended by all these UITestCase+Something extensions) and I have the test, that will do the login in LoginTests in which I am calling the login method from the UITestCase+Login extension. 为了更进一步 - 我有测试类和方法分为单独的文件 - 我有一个方法,将在UI测试中进行登录,所以我有UITestCase+Login扩展中的方法( UITestCase是一个类,即扩展了所有这些UITestCase+Something扩展)并且我有测试,它将在LoginTests中进行登录,我在其中从UITestCase+Login扩展调用login方法。

However - you don't necessarily need more test classes - if you decide to have all of your UI tests in one class, thats your choice. 但是 - 您不一定需要更多测试类 - 如果您决定在一个类中进行所有UI测试,那么这是您的选择。 Everything's gonna work, but having the tests and methods that these tests use in separate files is just a good practice for future development of tests and methods. 一切都会奏效,但是将测试和方法用于单独的文件只是测试和方法未来发展的一个很好的实践。

2/ ... Add additional security like secondary email address... How should these be ordered? 2 / ... Add additional security like secondary email address... How should these be ordered?

Order them into methods and call these in tests. 将它们分配到方法中并在测试中调用它们。

This is my method for expecting some UI message, when I use invalid login credentials: 当我使用无效的登录凭据时,这是我期待一些UI消息的方法:

func expectInvalidCredentialsErrorMessageAfterLoggingWithInvalidBIDCredentials() {
    let alertText = app.alerts.staticTexts[localizedString("mobile.account.invalid_auth_credentials")]
    let okButton = app.alerts.buttons[localizedString("common.ok")]

    wait(
        until: alertText.exists && okButton.existsAndHittable,
        timeout: 15,
        or: .fail(message: "Alert text/button are not visible.")
    )
    okButton.tap()
}

And this is my use of it in test: 这是我在测试中使用它:

func testTryToLoginWitMissingBIDAndExpectError() {
    let inputs = BIDLoginInputs(
        BID: "",
        email: "someemail@someemail.com",
        departureIATA: "xxx",
        dayOfDeparture: "xx",
        monthOfDeparture: "xxx",
        yearOfDeparture: "xxx"
    )

    loginWithBIDFromProfile(inputs: inputs)
    expectInvalidCredentialsErrorMessageAfterLoggingWithInvalidBIDCredentials()
}

You can see, that tests are very readable and that they (almost fully) consists of methods, which are re-usable in more tests. 您可以看到,测试非常易读,并且它们(几乎完全)由方法组成,这些方法可在更多测试中重复使用。

3/ Within the test target, should you have multiple files? 3 / Within the test target, should you have multiple files?

Again - this is up to you, however having everything in one file is not really good for maintenance and future development of these tests. 再次 - 这取决于你,但是在一个文件中包含所有内容对于维护和这些测试的未来开发并不是很好。

4/ ... Each time we run the test suite from the beginning the app starts in a state where you are not logged in...Right now I have it setup so that the login test runs once, then all other tests after it, then ends with logout... 4 / ... Each time we run the test suite from the beginning the app starts in a state where you are not logged in...Right now I have it setup so that the login test runs once, then all other tests after it, then ends with logout...

Not a good approach (in my humble point of view ofc.) - put the functionality into methods (yes, I repeat myself here :-) ) and divide the test cases into more files (ideally by the nature of their functionality, by "what they do"). 不是一个好的方法(在我看来很简单的观点。) - 将功能放入方法(是的,我在这里重复:-))并将测试用例分成更多的文件(理想情况是它们的功能性质,“他们做什么”)。

Hope, this helped you, I struggled a lot with the same questions, when I was starting with iOS UI tests too. 希望,这对你有帮助,当我开始使用iOS UI测试时,我也遇到了同样的问题。 Oh. 哦。 And btw - my article on medium.com about advanced tactics and approaches to iOS UI tests with XCTest is coming out in a few days, I can put a link to it, once it is out - that should help you even further. 顺便说一下 - 我在media.com上关于XCTest的iOS UI测试的高级策略和方法的文章将在几天内发布,我可以在它出来之后给它一个链接 - 它应该会帮助你更进一步。

Echoing this answer , it is against best practices to store all of your tests for a complex application in a single file, and your tests should be structured so that they are independent of each other, only testing a single behaviour in each test. 回答这个答案 ,将复杂应用程序的所有测试存储在单个文件中是违反最佳实践的,并且您的测试应该是结构化的,以便它们彼此独立,只测试每个测试中的单个行为。

It may seem counter-intuitive to split everything up into many tests which need to go through re-launching your app at the beginning of every test, but this makes your test suite more reliable and easier to debug as the number of unknowns in a test is minimised by having smaller, shorter tests. 将所有内容拆分成许多测试似乎都是违反直觉的,这些测试需要在每次测试开始时重新启动应用程序,但这会使测试套件更可靠,更容易调试,因为测试中的未知数量通过更小,更短的测试来最小化。 Since UI tests take a relatively long time to run, which can be frustrating, you should try to minimise the amount that you need by ensuring your app has good unit/integration test coverage. 由于UI测试需要相对较长的时间才能运行,这可能令人沮丧,因此您应该尝试通过确保应用程序具有良好的单元/集成测试覆盖率来最小化所需的数量。

With regards to best practices on structuring your XCTest UI tests, you should look into the Screenplay or Page Object models. 关于构建XCTest UI测试的最佳实践,您应该查看Screenplay或Page Object模型。 The Page Object model has been around a long time, and there are many posts around it although many tend to be focused on Selenium or Java-based test frameworks. 页面对象模型已经存在很长时间了,虽然许多帖子都倾向于关注Selenium或基于Java的测试框架,但它有很多帖子。 I have written posts on both the Page Object model and the Screenplay model using Swift and XCTest, they should help you. 我使用Swift和XCTest在Page Object模型Screenplay模型上写过帖子,他们应该帮助你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM