Introduction
XCTest is Apple's official framework for unit and UI testing on iOS, macOS, and tvOS. It lets you verify that your code behaves as expected before launching the app. In this tutorial, we will create a test target, write simple assertions, and run tests directly inside Xcode. Mastering XCTest from the beginning improves code quality and reduces regressions during updates.
Prerequisites
- Xcode 16 or later
- Basic knowledge of Swift
- An existing iOS project (or a new empty project)
Add a Test Target
// In Xcode: File > New > Target...
// Choose iOS Unit Testing Bundle
// Name: MyAppTests
// Language: SwiftCreating a separate test target isolates test code from production code and enables Xcode's built-in code coverage tools.
Create the Test Class
import XCTest
@testable import MyApp
final class MyAppTests: XCTestCase {
override func setUpWithError() throws {
// Code executed before each test
}
override func tearDownWithError() throws {
// Code executed after each test
}
}The class inherits from XCTestCase. setUp and tearDown ensure a clean environment for every test.
Write a Simple First Test
func testAddition() throws {
let result = 2 + 2
XCTAssertEqual(result, 4, "Addition should return 4")
}XCTAssertEqual is the most common assertion. The error message only appears when the test fails.
Test a Real Function
// Source file
struct Calculator {
func multiply(_ a: Int, _ b: Int) -> Int {
return a * b
}
}We test a real function from the main project by importing the module with @testable.
Add the Test for the Function
func testMultiply() throws {
let calc = Calculator()
let result = calc.multiply(3, 4)
XCTAssertEqual(result, 12)
}Every method starting with test is automatically executed by Xcode.
Best Practices
- Name your tests descriptively (testFunctionName_Scenario_ExpectedResult)
- Test only one behavior per method
- Use @testable import to access internal types
- Run tests on every commit via Xcode or the command line
Common Mistakes to Avoid
- Forgetting to import the module with @testable
- Using hard-coded values without clear setup
- Not testing edge cases (0, nil, negative values)
- Leaving tests that depend on execution order
Going Further
Discover our complete courses on iOS and Swift testing: https://learni-group.com/formations