The ultimate guide to unit and UI
testing for beginners in Swift
import XCTest
@testable import Example
class ExampleTests: XCTestCase {
override func setUp() {
XCTAssertTrue(true)
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}
func validate(email: String) -> Bool
"example@address.com" -> true
"my.personal.address@google.co.uk" -> true
"" -> false
"invalid@address." -> false
"lorem ipsum dolor sit amet" -> false
"injection@example.com; DROP TABLE users" -> false
"✉️" -> false
"23983ujnvmfbbg73209refagjklnku129@adf@asdf.com" -> false
XCTAssert(validator.validate(email: "my.personal.address@google.co.uk") == true)
XCTAssertTrue(validator.validate(email: "example@address.com"))
XCTAssertFalse(validator.validate(email: ""))
XCTAssertEqual(validator.validate(email: "invalid@address."), false)
XCTAssertNotEqual(validator.validate(email: "lorem ipsum dolor sit amet"), true)
func testAsyncMethod() {
let expectation = XCTestExpectation(description: "We should wait for the sample async method.")
mySampleAysncMethod(delay: 2, response: "Hello Async!") { [weak expectation] result in
XCTAssertEqual(result, "Hello Async!")
expectation?.fulfill()
}
self.wait(for: [expectation], timeout: 3)
}
func testSlowMethod() {
self.measure {
for _ in 0..<100 {
slowMethodCall()
}
}
}
import XCTest
class TestUITests: XCTestCase {
override func setUp() {
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
continueAfterFailure = false
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testExample() {
// UI tests must launch the application that they test.
let app = XCUIApplication()
app.launch()
// Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testLaunchPerformance() {
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) {
// This measures how long it takes to launch your application.
measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) {
XCUIApplication().launch()
}
}
}
}
// in your application target...
class ViewController: UIViewController {
@IBOutlet weak var resultLabel: UILabel!
@IBOutlet weak var inputField: UITextField!
@IBOutlet weak var submitButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
self.resultLabel.accessibilityIdentifier = "result-label"
self.inputField.accessibilityIdentifier = "input-field"
self.submitButton.accessibilityIdentifier = "submit-button"
}
}
// in your ui test target...
private 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 = "Hello world"
app.inputField.tap()
app.inputField.typeText(expectation)
app.submitButton.tap()
XCTAssertTrue(app.staticTexts[expectation].exists)
}
}
import UIKit
func scene(_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else {
return
}
let window = UIWindow(windowScene: windowScene)
let processInfo = ProcessInfo.processInfo
var moduleName = "Main"
if processInfo.arguments.contains("-test") {
if let name = processInfo.environment["module"] {
moduleName = name
}
}
window.rootViewController = UIStoryboard(name: moduleName, bundle: nil).instantiateInitialViewController()
self.window = window
self.window?.makeKeyAndVisible()
}
import XCTest
extension XCUIApplication {
static func launchTest(module: String = "Main") -> XCUIApplication {
let app = XCUIApplication()
app.launchArguments = ["-test"]
app.launchEnvironment = ["module": module]
app.launch()
return app
}
}
func testHello() {
let app = XCUIApplication.launchTest(module: "Hello")
XCTAssertTrue(app.staticTexts["Hello"].exists)
}
if processInfo.arguments.contains("-test") {
UIView.setAnimationsEnabled(false)
self.window?.layer.speed = 100
}