HomeiOS DevelopmentThe final word information to unit and UI testing for freshmen in...

The final word information to unit and UI testing for freshmen in Swift


Learn to write real-world Unit/UI check instances to your iOS app. This one is a sensible 101 testing article for absolute freshmen.

Bitrise

Automated testing utilizing Xcode

In case you are working with Xcode you’ll be able to arrange two sorts of testing bundles:


Unit checks

Testing particular person software program parts known as unit testing. This sort of testing is normally executed by the programmer and never by testers, as a result of it requires an in-depth information of the app’s inside design.


UI (person interface) checks

UI testing helps you to check interactions with the graphical person interface to be able to validate the GUI in opposition to the enterprise necessities, so principally checking if the buttons truly work or not.


Different forms of testing

There are many different forms of testing, however on this article I am not going to focus an excessive amount of on them since I am working with Xcode bundles. It is value mentioning although that you would be able to make your personal e.g. regression check bundle by utilizing the built-in check bundles. In case you are interested in another methods of validating your software program you could find a short abstract right here.



Faux, mock, stub, oh my spy… 😐

Earlier than we dive into sensible testing, we have to make clear some ideas. A lot of builders are confused with these phrases, and I am not judging anyone, since they are often simply misinterpreted. In my dictionary:


Faux

A pretend has the identical conduct because the factor that it replaces.

Faux objects are nearer to the actual world implementation than stubs. Which means that pretend objects normally have the identical conduct because the factor that they exchange. For instance a pretend login can return a pretend token similar to an precise API service would do (with actual knowledge in fact). They’re helpful if you would like to run checks, since a complete service layer may be changed utilizing these objects.


Stub

A stub has a “fastened” set of “canned” responses which can be particular to your check(s).

Stub objects are normally hardcoded values which can be anticipated in some sort of check instances. They’re actually dumb, they do not comprise a lot logic, they’re simply pre-programmed objects with some fastened set of information. If I’m going again to our pretend authentication instance, the response could be a stub authorization token object together with some random person knowledge.


Mock

A mock has a set of expectations for calls which can be made. If these expectations will not be met, the check fails.

Mock objects can exchange whole courses and so they present the flexibility to test if specific strategies or properties have been referred to as or not. They will additionally return stub values as defaults, errors or throw exceptions if wanted. A mock has a set of expectations for calls, you’ll be able to test these expectations in your checks, if these will not be met, your check ought to fail.


Spy

Whenever you use a spy then the actual strategies are referred to as.

Spy objects can actually spy on present objects or strategies. That is helpful when you may have a much bigger class and you do not need to mock the whole lot, however you might be interested in some smaller piece of the inner conduct of that object. You possibly can think about spy objects as wrappers round an present class. They do some spying and so they name the unique implementation afterwards.



Unit testing in follow

Now that you understand the fundamentals, let’s write some sensible UI/Unit checks in Swift. ⌨️


Wait… what the heck is a check?

Effectively the brief reply a check is a operate that may have two distinct outcomes:

  • ✅ – success
  • ❌ – failure

Defining good a unit check is difficult, however thankfully Vadim has some glorious articles about this matter, so you need to positively test his weblog as nicely. 😉


The anatomy of a unit check goal in Xcode


A number of check instances may be grouped collectively inside a category in Xcode. It is a neat technique to write associated checks for a software program part. Simply import the XCTest framework, (which can be accessible for Linux), subclass the XCTestCase class and prefix your check strategies with the check key phrase to have the ability to check them. 🔨


The setUp and tearDown strategies will probably be referred to as earlier than each single check operate, however normally I do not like to make use of them, I all the time provoke a brand new setting for my checks for each single case. The explanation behind that is that checks can run in parallel, which is absolutely superb when you’ve got a number of them. Additionally you do not need to find yourself with some damaged check case, simply due to some silly shared state or aspect impact.


Additionally you need to observe that you need to import your app goal as @testable import Goal in your check goal so as to have the ability to attain your objects & strategies. This fashion you can check your inside courses and strategies as nicely. 📝


import XCTest
@testable import Instance

class ExampleTests: XCTestCase {

    override func setUp() {
        XCTAssertTrue(true)
        
    }

    override func tearDown() {
        
    }

    func testExample() {
        
    }

    func testPerformanceExample() {
        
        self.measure {
            
        }
    }

}



How ought to I write a check?

Think about a technique that validates an electronic mail deal with, which has an enter parameter (String), and a return worth (Bool). We do not care in regards to the internals proper now, this methodology is a black field, perhaps another person will write it, perhaps you’ll, from the purpose of unit testing it would not matter. Simply take into consideration the interface for now:

func validate(electronic mail: String) -> Bool

Okay, so we’ve got our operate prototype, now take into consideration what sort of inputs can we give this operate, and what is going on to be the anticipated output:


The aim of a unit check is to catch all the sting instances. The built-in XCTest framework has some useful strategies to judge your checks. So for instance, if you wish to make a easy unit check to test the outcome in opposition to the enter examples from above, you could possibly use the next features to judge your outcomes:


XCTAssert(validator.validate(electronic mail: "[email protected]") == true)
XCTAssertTrue(validator.validate(electronic mail: "[email protected]"))
XCTAssertFalse(validator.validate(electronic mail: ""))
XCTAssertEqual(validator.validate(electronic mail: "[email protected]"), false)
XCTAssertNotEqual(validator.validate(electronic mail: "lorem ipsum dolor sit amet"), true)


You may as well present a customized failure message as a final parameter for each single assertion methodology, however normally I am simply positive with the default worth. 🤷‍♂️


What sort of unit checks ought to I write?

Effectively my fast reply is to consider the next eventualities first:

  • a case that’ll match your expectation (legitimate case)
  • invalid case (one thing that ought to elevate an error / exception)
  • edge instances (limitations like higher bounds of an integer)
  • harmful instances (particular inputs which may break your code)
  • monkey checks (check with fully random values)

As you’ll be able to see, for the e-mail validation instance I principally adopted these fundamental guidelines. Simply take into consideration the pretty easy use instances, the principle aim right here is to not cowl each single one in every of them, however to get rid of probably the most crucial eventualities.


What about async strategies?

You possibly can check async strategies as nicely utilizing an expectation. You would possibly ask now:

What’s an expectation?

In case you heard about futures and guarantees, you may see that expectations are considerably comparable, besides that you do not have to supply a achievement worth and so they can by no means fail, however timeout. Vadim additionally has some good articles about unit testing async code in Swift and the busy assertion sample. I am not going into the main points, since we’ve got to cowl much more, however right here is how one can watch for one thing to occur:


func testAsyncMethod() {
    let expectation = XCTestExpectation(description: "We should always watch for the pattern async methodology.")

    mySampleAysncMethod(delay: 2, response: "Hi there Async!") { [weak expectation] outcome in
        XCTAssertEqual(outcome, "Hi there Async!")
        expectation?.fulfill()
    }
    self.wait(for: [expectation], timeout: 3)
}


As you’ll be able to see, you simply need to outline your expectation(s) first, you then wait for them utilizing the wait methodology with a given timeout parameter. When your async methodology returns with a callback, you’ll be able to name fulfill in your expectation to mark it prepared. In case your expectations will not be prepared earlier than the timeout… nicely the check will fail. ☹️


Measure your code

Measurements are an effective way to hurry up slower elements of your software. When you have a technique that appears to be sluggish, you’ll be able to put it inside a measure block to test its timings. You may as well iterate the tactic a couple of (hundred) occasions, this fashion you will get a greater baseline quantity.


func testSlowMethod() {
    self.measure {
        for _ in 0..<100 {
            slowMethodCall()
        }
    }
}


If you wish to know extra about measurements you need to learn this superb article by Paul Hudson about how one can optimize sluggish code.

Run your check & set a baseline by clicking the little grey indicator on the left. Subsequent time your check runs you may see how a lot the code improved or wicked since final time.


When to jot down checks?

Writing a check takes time. Time is cash. ⏳ = 💰

I haven’t got time for checks (press CMD+R to check a characteristic…)

However it could additionally prevent a whole lot of time, since you do not have to rebuild / rerun your whole software simply to see if a operate works or not. In the long run, it is positively value it to have these checks for at the very least the enterprise logic of your software. Within the brief time period you would possibly say you do not have the time, however after a couple of hundred handbook checks you would possibly end up in a state of affairs like this:

Oh man right here we go once more… (presses CMD+R to check a characteristic…)


TDD vs the common method?

I might say when you’ve got a extremely good specification and also you already understand how you’ll construct up your software it is secure to go together with TDD and even BDD. In any other case if the challenge is “agile” (which means you may have fixed modifications in your necessities) it could lead you to place a whole lot of work into fixing your code AND your check instances.


When to check?

Anyway, in case you made the choice and you might be prepared to jot down your checks, right here is my nr.1 tip: do not transfer on creating the following characteristic till you’ve reached your required protection, in any other case you may have an enormous tech debt sooner or later. I do know this for certain, I have been there, you do not need to make this error, as a result of it isn’t enjoyable to jot down a whole bunch of unit checks directly. Even a couple of actually fundamental checks for a single performance is best than zero.


What to check?

I might say that you need to check primarily your enterprise layer utilizing unit checks. This could be a presenter, or particular features inside a view controller, a supervisor or a service. It actually would not matter the place the implementation is, however till it does some sort of “calculation” it is all the time good to have check instances to validate that piece of code.

Additionally you’ll be able to’t merely cowl the whole lot with unit checks, typically you need to test some options that require person interactions…



UI testing in follow

Now that you’ve got a greater understanding about how unit testing works, let’s discuss UI checks. These sorts of checks are actually helpful in case you do not need to spend your time with the boring repetitive activity of making an attempt out stuff in your telephone on a regular basis throughout growth. Excellent news is that the iOS simulator can deal with most of that.


The anatomy of a UI check goal in Xcode

So as to have the ability to run UI checks, you need to arrange a brand new goal to your challenge. Here’s a fast information that’ll present you the method if you do not know how one can do it.


import XCTest

class TestUITests: XCTestCase {

    override func setUp() {
        
        continueAfterFailure = false

        
    }

    override func tearDown() {
        
    }

    func testExample() {
        
        let app = XCUIApplication()
        app.launch()

        
    }

    func testLaunchPerformance() {
        if #accessible(macOS 10.15, iOS 13.0, tvOS 13.0, *) {
            
            measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) {
                XCUIApplication().launch()
            }
        }
    }
}


A UI check bundle is dynamically injected into your software, so you’ll be able to’t merely provoke a view controller occasion for instance, however you need to use a particular technique to attain your UI parts and carry out actions on them by means of:


Accessibility

Each single UI factor has an accessibilityIdentifier property by default. It is a string that uniquely identifies that view. Afterward you’ll be able to question the view occasion by utilizing the beforehand related accessibility identifier, which is available in actually useful since you aren’t allowed to provoke views straight.

There’s a particular XCUIApplication (a reference to your operating software) object that has some useful properties to question references to varied person interface parts, comparable to buttons, photos, assortment views, and so forth., you’ll be able to test the whole accessibility cheat-sheet right here, however I will present you some examples in a while.

Okay, however what occurs after I do not need to use accessibilityIdentifiers? Can I merely seize the UI hierarchy by some means and do some actions with out coding?


Ought to I document my UI checks?

Effectively, the factor is that you would be able to simply press the document button in Xcode and the system will seize all of your person interactions routinely, however please do not do this.

Why do I favor coding? Effectively:

  • the UI testing API is fairly easy
  • writing complicated UI checks will probably be method sooner in case you study the accessibility API
  • typically you will not be capable of seize what you need utilizing the recorder
  • utilizing identifiers as an alternative of captured labels are higher (for localized checks)
  • you do not all the time need to get by means of the identical course of time and again
  • studying new issues is enjoyable, a brand new API means extra information! 😀

Let’s try how easy it’s to jot down some UI checks…


Writing iOS UI checks programmatically

I favor to make use of accessibility identifiers for a number of causes. It isn’t only a very nice factor to make your app accessible for a a lot wider viewers, however in case you arrange each factor correctly accessible, writing UI checks will probably be a bit of cake, since you’ll be able to question the whole lot by its distinctive identifier. Let me present you a fast instance.



class ViewController: UIViewController {

    @IBOutlet weak var resultLabel: UILabel!
    @IBOutlet weak var inputField: UITextField!
    @IBOutlet weak var submitButton: UIButton!

    override func viewDidLoad() {
        tremendous.viewDidLoad()

        self.resultLabel.accessibilityIdentifier = "result-label"
        self.inputField.accessibilityIdentifier = "input-field"
        self.submitButton.accessibilityIdentifier = "submit-button"
    }
}


personal extension XCUIApplication {
    var inputField: XCUIElement { self.textFields["input-field"] }
    var submitButton: XCUIElement { self.buttons["submit-button"] }
}

class TestUITests: XCTestCase {

    func testSubmitValue() {
        let app = XCUIApplication()
        app.launch()

        let expectation = "Hi there world"
        app.inputField.faucet()
        app.inputField.typeText(expectation)
        app.submitButton.faucet()

        XCTAssertTrue(app.staticTexts[expectation].exists)
    }
}


As you’ll be able to see I prolonged the XCUIApplication class, since I do not need to take care of identifiers time and again. It is a kind of good / unhealthy habits I picked up since I needed to write a number of UI check instances. I am not 100% certain about it but, perhaps there’s a higher method however for me it was fairly handy and turned out to be actually useful. It is also personal anyway so nobody else can see it. 🤫

Querying accessible person interface parts is so simple as utilizing these extension properties, which is ridiculously handy. You need to use the accessible strategies and properties on these XCUIElement situations, comparable to exists, faucet, typeText, nonetheless you could find another challenges throughout the street:


Deal with alerts

The primary impediment for me was interacting with iOS alert home windows. Thankfully Keith Harrison has a terrific article about dealing with system alerts in UI checks. It’s best to positively test if you’re operating into the identical problem.


Scroll to cell

One other deal breaker is to simulate scrolling conduct. Since accessibility actions are restricted to faucets and fundamental UI actions, this snippet helped me loads.


Person enter

Getting into person enter may be fairly difficult, since you need to give attention to the enter subject first, however provided that the sector is just not chosen but, so watch out. You must also observe that plain textual content fields and safe textual content fields are separated into two distinct properties within the XCUIAppliaction object. Additionally placeholders are sort of tough ones, as a result of the placeholderValue property modifications in case you enter some textual content. ⚠️


Change system preferences

One humorous factor that you are able to do with UI testing is to alter a system choice by altering iOS settings. Right here you’ll be able to test how one can work together with the settings app.


The way to write UI checks?

Effectively, there is no such thing as a definitive reply, as a result of your person interface is exclusive to your software. Actually all of it relies on you and your designer, however for me the important thing issue was utilizing accessibility identifiers and getting used to the accessibility queries and APIs. I feel it was value studying it, I can solely encourage you to get acquainted with the framework and mess around only a few hours, you will not remorse it. 😉


When to jot down UI checks?

It relies upon (do not hate me). These days, I favor to have a check for all of the options I am engaged on, however typically I notice that I am merely tapping by means of my app doing handbook testing. Outdated habits die arduous, proper? 😂

Ah overlook it, simply write checks if you wish to save time in the long run. Within the brief time period you may solely see that the whole lot takes longer to realize, however belief me if it involves bugs or surprising behaviours, having these checks can pay out massively. 💵



Steady integration and testing

On this part I’ll focus (slightly bit) on Bitrise, since I feel they supply the perfect CI service available on the market for iOS builders proper now. 📱


Take a look at studies

They’re engaged on some cool new (beta) options referred to as Add-ons. One in every of them is specializing in check studies. This implies that you would be able to see the end result of your checks straight from the construct dashboard. The report display will give you a fast abstract of all of the profitable and failed checks outcomes, however you’ll be able to filter them by standing manually or test particular person check instances as nicely. Tremendous good, I find it irresistible. ❤️


Bitrise test results



Code protection

In pc science, check protection is a measure used to explain the diploma to which the supply code of a program is executed when a specific check suite runs.

Some say it is nothing only a quantity or a bunch of numbers. Effectively, if it is true then why do individuals use analytics software program on a regular basis? I feel code protection needs to be enabled in each single Xcode challenge by default.

There are some instruments referred to as xccov and slather. In case you run them on the CI and make the report accessible to your QA crew, they will actually see which a part of the app wants extra testing and what’s already checked by the automated checks. I feel this can be a actually beneficial perception, however sadly most firms do not “have the sources” for devoted QA (and UX) groups. 🧠


Pull requests & automated code evaluation

One other good factor is that you would be able to run your checks earlier than you merge your modifications into a selected department. This fashion you’ll be able to be sure that nothing critical is damaged within the challenge. Automated checks and code evaluation is a should on the subject of teamwork.

It actually would not matter in case your crew may be very little or an enormous one engaged on an unlimited codebase, security is all the time security. Begin using the facility of automation at the moment, do not waste your time on boring, repetitive duties. It will assist your crew loads. 👍



Unit / UI testing finest practices

Once more I’ve to provide some credit score to Vadim, since he collected a pleasant record of unit testing finest practices on iOS with Swift. My record will probably be slightly bit totally different…

All the time run checks in parallel

As I discussed earlier than, you need to use parallel testing to be able to velocity up the entire course of. This implies that you would be able to’t share states between checks, which is an effective factor. Do not be afraid, simply initialize a brand new “setting” for each single time to your SUT (system underneath testing). If you do not know how one can arrange parallel testing, you need to learn this text.


Use the brand new check plans format

There’s a new factor in Xcode 11 referred to as check plans. It provides higher help for testing a number of localisations, arguments, setting and a lot extra. I do not need to write down the tactic of changing to the brand new format, as a result of there may be one other weblog put up written about Take a look at Plans in Xcode 11, I extremely suggest it.


Use mock / pretend / stub / spy objects

Do not use growth / manufacturing environments, however implement your personal simulated service layers (API, sensors e.g. CoreLocation, Bluetooth, and so forth.). You need to use a manufacturing unit design sample or dependency injection to realize this conduct. This fashion you’ll be able to management the returned knowledge and you do not have to attend for laggy networks. Utilizing a managed setting for checks is the suitable technique to go. Be at liberty to make use of as a lot mock / pretend / stub / spy object as you want, return errors or failures if wanted and preserve your delays and timeouts low to complete your checks sooner.


Solely launch a selected display for UI testing

When you have a big software with a number of screens you do not normally need to run by means of the whole login / onboarding process that you just normally need to throughout a clear begin, however you simply need to check the display that you’re engaged on. Is that this doable? Can I do this? Is that even authorized? 🤔

Haha, completely! With a view to launch a customized display first you need to put together your app goal to help it. You need to use the launch arguments or the method information property to test if a selected key exists and current a display based mostly on that. This requires slightly bit extra work, additionally you need to be capable of determine all of your screens by some means if you wish to do that, however that is why we’ve got routers, am I proper? #viper

Let me present you actually rapidly how one can make it work.


import UIKit

func scene(_ scene: UIScene,
           willConnectTo session: UISceneSession,
           choices connectionOptions: UIScene.ConnectionOptions) {

    guard let windowScene = scene as? UIWindowScene else {
        return
    }
    let window = UIWindow(windowScene: windowScene)
    let processInfo = ProcessInfo.processInfo
    var moduleName = "Important"
    if processInfo.arguments.comprises("-test") {
        if let title = processInfo.setting["module"] {
            moduleName = title
        }
    }
    window.rootViewController = UIStoryboard(title: moduleName, bundle: nil).instantiateInitialViewController()
    self.window = window
    self.window?.makeKeyAndVisible()
}


In your SceneDelegate.swift file you need to instantiate your personal display (or ought to I name it module?) and move it to the window. The snippet above does the very same factor. First it checks if the processInfo comprises the -test flag, if that is true it’s going to attempt to load the given module from the setting.

It is fairly easy, however nonetheless we’ve got so as to add help for launching our software from the UI check goal with these parameters. Let’s make an extension for that.


import XCTest

extension XCUIApplication {

    static func launchTest(module: String = "Important") -> XCUIApplication {
        let app = XCUIApplication()
        app.launchArguments = ["-test"]
        app.launchEnvironment = ["module": module]
        app.launch()
        return app
    }
}


Right here is how one can use the extension in follow:


func testHello() {
    let app = XCUIApplication.launchTest(module: "Hi there")

    XCTAssertTrue(app.staticTexts["Hello"].exists)
}


By utilizing this method you can begin with a given display, however nonetheless you would possibly have to pretend / mock / stub some providers or properties, since it isn’t an strange software launch. Needless to say you’ll be able to move a number of setting variables round, and you’ll all the time test the arguments if it comprises a given flag. 😉


Pace up your UI checks by disabling animations

This one can actually prevent a whole lot of time and it is very straightforward to implement.


if processInfo.arguments.comprises("-test") {
    UIView.setAnimationsEnabled(false)
    self.window?.layer.velocity = 100
}


See? Just some traces of code, however the velocity affect may be huge. 🚀


Designing your code for testability

Something is best than spaghetti code. MVP may be nicely examined, however some properly architected clear MVC sample can work as nicely. I just like the idea of presenters, since they encapsulate enterprise logic and normally the presentation logic may be examined and not using a trouble. Shifting one step additional…


VIPER

Right here comes the “insert abbreviation right here” vs the overcomplicated VIPER structure holy conflict once more… nope, not at the moment. I actually do not care about your structure of alternative. What I care about is testability, however you’ll be able to’t actually check a technique that has a excessive complexity fee.

If you wish to have good check protection, it is vital to separate your code into smaller chunks that may work collectively nicely. I all the time see unhealthy pattern codes with so many uncomfortable side effects, unhealthy operate APIs and lots of extra ugly practices. I do know that piece of code typically has historic causes, however different occasions the programmer was simply merely a lazy bastard. 😴

All the time take into consideration your future self (and different programmers). Think about that you need to return to your code in a yr or two… in case you write traces after traces with out pondering (and I may additionally say feedback, docs, check instances right here as nicely) you may need a whole lot of issues in a while, as a result of nobody will be capable of determine what you needed to realize.

Breaking your code into smaller useful items is a very powerful takeaway right here. This method may even be useful to your API designer mindset and the testability of your codebase.

In case you are utilizing VIPER you may have a very easy activity to do. Write unit checks solely to your presenter and interactor strategies. After all if you’re following my service layer based mostly VIPER method (Vapor is doing this as nicely and it is superb) you need to check your whole service layer API. It would not make an excessive amount of sense to unit check a UI part, or a routing conduct, you need to use the UI check bundle for these duties.


Work & check domestically, “regression” check on CI

I favor to solely run these checks domestically that I am engaged on. The whole lot else belongs to the continual integration server (CI). I do not need to waste my time and {hardware} by operating 500 checks on my mac, there is no such thing as a want for that. Setup a CI service and run your checks there whether or not it is regression, acceptance or integration.

You may as well run checks from the command line, plus if you should, you’ll be able to move round setting variables, for instance if you need to take care of delicate knowledge.



Conclusion

Some individuals love to jot down checks and a few individuals hate, however one factor is for certain: checks will make your code safer and extra dependable. When you have by no means written any checks earlier than I might say you need to begin forming a behavior and begin it now. Your entire steady integration and supply trade was born that will help you with this, so do not waste your treasured time… oh and begin utilizing Bitrise! 🤖


RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments