What is iOS Unit Testing? (Tutorial with Xcode & Swift)
On This Page Importance of iOS Unit TestingKey Benefits of
- Importance of iOS Unit Testing
- Key Benefits of iOS Unit Testing
- What can you test with Unit Testing?
- Getting Started with Development on App Store
- Figuring out What to Test in iOS App Unit Testing
- Configuring Xcode for iOS App Unit Testing
- Writing iOS Unit Tests
- Running Unit Tests from Xcode
- Unit Testing Integration with CI
- Best Practices for writing Effective Unit Tests
What is iOS Unit Testing? (Tutorial with Xcode & amp; Swift)
iOS Unit Testing is the process of testing individual ingredient (or units) of an iOS application, typically at the level of individual classes, methods, or part. The goal is to ensure that each part of the code act as expected in isolation.
Unit tests are written to control that the logic of the code behaves correctly in different scenario, which helps identify glitch early in the development operation.
Importance of iOS Unit Testing
Coding is a real abstract action if you sit down and conceive about it. Developing apps is an understandably complex procedure that affect, besides coding, the ability to audit your work and pass a few test and jump a few hoops before your employment is released for the world to enjoy.
- Most people who code find themselves embedded in the broader context of a university/company/learning grouping as a part of which they are coding respective programme.
- This intend they con from the citizenry and work environment they turn up in, which could be a great thing or a disaster, depending on the destiny.
- Software programs like iPhone and iPad apps are bundled hierarchical programmatic structures of information/instructions that perform many figuring as part of a running application procedure.
Swiftas a coding platform for Apple, like any other platform, has its strengths, weaknesses, and peculiarities. The job of an efficient programmer is to understand and contain the platform features, behavior and edge cases, directing them to work for the business or merchandise goal.
- This requires a deep cognition of the development and delivery platform end-to-end, on top a low suspicion towards one & # 8217; s own work and constant tryout activity running parallel to coding.
- Hence you will find rattling efficacious developers testing their codification incessantly and even developing ways to automate the process.
- The industry standard way of doing that is to write additional code with the supposed coating code, whose sole job is to test the application code along various desirable metrics.
That is, in essence, what is all about. But still, it is not that simple to generalize. Let & # 8217; s try and translate with the aid of some use cases.
Key Benefits of iOS Unit Testing
Performing unit testing in Xcode with XCTest framework offers several real-world, meaningful welfare for developers and organizations:
- Improved code quality: Unit tests help name bugs and errors early in the evolution process, ensuring that your codification is more reliable and rich.
- Faster development: When issues are caught early through unit testing, they can be fixed more quickly than if discovered later during manual examination or by end-users. This speeds up the overall growth process.
- Easier code maintenance: Well-structured unit tests document your codification, making it easier for other developers to understand and maintain the codebase.
- Best quislingism: Unit prove ensure that codification pen by multiple developers works together seamlessly, enhancing collaboration and reducing codebase conflicts.
- Reduced debugging time: Unit tests can help pinpoint the exact location of a bug or issue, importantly reducing the clip spent on debugging.
- Easier code refactoring: When you have a good set of unit tests, you can refactor your code more confidently, knowing that your modification won & # 8217; t introduce new topic.
- Test-driven ontogeny (TDD):Unit examination is a rudimentary part of, a development process where you write tests before writing the existent code. This approach can lead to cleaner, more efficient codification.
- Faster onboarding: Unit tests can help new developer understand the codebase faster by ply insights into the expected behavior of each element.
- Improved fixation testing: Unit tests can catch fixation betimes, ensuring that changes and updates to the codification don & # 8217; t break existent functionality.
- Cost savings: By catching and define issues early, unit tests can save time and money by reducing the demand for extensive manual testing and the risk of transport faulty codification to end user.
What can you test with Unit Testing?
In Xcode, you can use theXCTestfabric to write and execute unit exam for various components of your iOS, macOS, watchOS, or tvOS projects. With unit tests, you can test a wide range of aspects, include but not limited to:
- Functions and method: Test individual function and methods to ensure they return expected outputs for give comment and care edge cases appropriately.
- Performance: Test the performance of your code by measuring the time taken to execute specific chore or functions. This helps you identify bottlenecks and optimize your codification.
- Asynchronous code: Test asynchronous codification, such as network requests and culmination handlers, to ensure they complete successfully and return expected event.
- Data models: Test the behavior and consistency of your datum model, include validation, serialization, and deserialization.
- Business logic: Test the nucleus logic of your application to ensure it meets the needed specifications and behaves as expected.
- Code Coverage: Measure and analyze the portion of your cover by your unit tests to ensure a eminent level of test coverage.
- Mocking and stubbing: Use mock objects and stub to isolate specific components during testing, which help moderate dependencies and focus on the component under test.
- UI element: While unit tests primarily focus on non-UI codification, you can likewise test some aspects of your UI components, such as their initial province and interaction with early objects.
Remember that unit tests are meant to test small, isolated piece of codification. For more comprehensive testing of your application & # 8217; s user interface and interaction, you should useUI examination within the XCUIframework.
Getting Started with Development on App Store
To test your application using TestFlight, habitus and render using CI/CD and eventually deploy it to the Apple App Store, you will need to get the following steps fulfilled:
- Go to the Apple Developer siteand click on & # 8220; Account & # 8221; in the top right menu bar.
- Sign in with your Apple ID or create a new one if you don & # 8217; t have one.
- Click on the & # 8220; Enroll & # 8221; or & # 8220; Join & # 8221; option to start enrollment.
- It will tell you to downloadApple Developer Appto continue.
- Choose the appropriate rank tier and chink on & # 8220; Start Your Enrollment. & # 8221;
- Follow the on-screen instructions to complete the enrollment process and pay the yearly fee.
- Once inscribe, you can download Xcode from the Mac App Store and start developing your apps for the Apple ecosystem.
- After you experience establish Xcode, open it and sign in with your Apple Developer account.
- You are now ready to germinate and test your applications using Xcode and TestFlight.
- You can also use like Jenkins, Travis CI, or CircleCI to build and deliver your applications.
Once your app is reviewed and O.K., you can free it to the App Store.
Figuring out What to Test in iOS App Unit Testing
To make this section comp, rather of do lists, let & # 8217; s make a very simple app in Xcode and then use it as a subject for understanding iOS Swift unit examination.
Setup Application Code
For our iOS Unit Test exemplar, we will setup a simple app that does the following:
- Setup a control file in Xcode
- Setup a perspective file in Xcode
- Define a simple form with 2 number inputs and a button
- Entering figure and clicking button testify the sum in a popup
The terminal code looks like this:
BrowserStackDemo/ BrowserStackDemoApp.swift
import SwiftUI import UIKit @ master struct MyCalculatorApp: App {var body: some Scene {WindowGroup {ContentView (controller: CalculatorController ())}}} class CalculatorController: ObservableObject {@ Published var firstNumber: String = `` '' @ Published var secondNumber: String = `` '' @ Published var result: Int = 0 func calculateSum () {if let initiatory = Int (firstNumber), let second = Int (secondNumber) {result = first + second showAlert ()}} func showAlert () {let alert = UIAlertController (rubric: `` Result '', message: `` The sum is \ (result) '', preferredStyle: .alert) alert.addAction (UIAlertAction (title: `` OK '', style: .default)) if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let window = windowScene.windows.first {window.rootViewController? .present (spanking, animated: true, completion: nil)}}} struct MyContentView: View {@ ObservedObject var controller: CalculatorController var body: some View {VStack {TextField (`` First act '', text: $ controller.firstNumber) .padding () TextField (`` Second number '', text: $ controller.secondNumber) .padding () Button (action: controller.calculateSum) {Text (`` Calculate '')}}}}This codification delineate a basic calculator app with a user interface implement using SwiftUI, which countenance user to input two numbers and calculate their sum.
Here & # 8217; s a summary of what each portion of the codification does:
- @ main struct MyCalculatorApp: App: Defines the main app structure and the launching point for the app.
- class CalculatorController: Implements the app & # 8217; s logic by calculating the sum of the two input numbers and presenting an alert with the resultant.
- func showAlert (): Presents an alert with the calculation resultant.
- struct MyContentView: View: Defines the app & # 8217; s user interface apply SwiftUI.
- TextField and Button elements: Provide text input fields for the user to input the two numbers, and a button to actuate the sum calculation.
- calculateSum (): Performs the calculation of the sum of the two comment numbers using the Int () initializer to convert the input strings to integers.
BrowserStackDemo/ ContentView.swift
meaning SwiftUI struct ContentView: View {@ ObservedObject var restrainer: CalculatorController var body: some View {VStack {Text (`` Addition Calculator '') .font (.title) .padding () HStack {TextField (`` Enter first number '', text: $ controller.firstNumber) .padding () .keyboardType (.numberPad) TextField (`` Enter second routine '', text: $ controller.secondNumber) .padding () .keyboardType (.numberPad)} Button (`` Calculate '') {controller.calculateSum ()} .padding () .foregroundColor (.white) .background (Color.blue) .cornerRadius (10)}}}- This codification delimitate aSwiftUIview that displays a canonical addition figurer with two text fields for entering two numbers and a button to perform the addition.
- It direct an instance ofCalculatorControlleras an ascertained objective to care the computing and expose the result.
Finally, running the app in the simulator gives us this output:
Configuring Xcode for iOS App Unit Testing
As mentioned earlier, unit examination can be initialized by but choose the “ include tests ” option while creating a new task.
If you desire to create the test classes manually subsequently, you can:
Step 1. Click on the project navigator on the left-hand side of Xcode.
Step 2. Right-click on the group or pamphlet where you want to add a new test file.
Step 3. Choose & # 8220;New File& # 8221; from the contextual menu.
Step 4. Select the & # 8220;Test Case Class& # 8221; template from the & # 8220;iOS& # 8221; or & # 8220;macOS& # 8221; category.
Step 5. Click & # 8220;Next& # 8221; and name your examination file.
Step 6. Select the appropriate prey and click & # 8220;Create“.
Writing iOS Unit Tests
Pro tip: Tools like SUSA can handle this autonomously — upload your app and get results without writing a single test script.
The default test file templates for both unit and UI tests in Xcode provide a starting point for developers to make their tests. In the case of unit exam, the templet includes a sample examination case with a test part and a setUp and tearDown mapping.
The setUp function is executed before each test function and is employ to set up any required resources or objects for the test case. The tearDown function is executed after each examination function and is used to clean up any imagination or objects used by the test case.
1. Test Functional Logic
Our test file ‘ BrowserStackDemoTests /BrowserStackDemoTests.swift ’ moderate the functional tests for the app, the first unit test we will write is supposed to check for the result of the sum and match it against a specific output for given remark:
func testCalculateSum () {let controller = CalculatorController () controller.firstNumber = `` 2 '' controller.secondNumber = `` 3 '' controller.calculateSum () XCTAssertEqual (controller.result, 5)}This trial creates a new instance of theCalculatorControllerclass, sets itsfirstNumber and secondNumberproperties, calls thecalculateSum() method to forecast the sum, and then checks if the result property is adequate to the expected value of “ 5 ” expend theXCTAssertEqual function.
While XCAssertis a utilitarian function for writing unit tests, it & # 8217; s important not to rely on it too heavily. In some cases, it may be more appropriate to use other techniques for validating test results, such as:
- Checking the province of an object after a method has be called
- Using conditional statements to check for expected demeanour
- Logging or print debug information for manual inspection
XCAssertcan merely be used within a single exam method, and it can & # 8217; t be apply to test asynchronous behavior. Understanding these limitations and utilise the appropriate testing techniques for each situation is crucial.
2. Test with mock UIWindow
For the next tryout, we will test the alert after sum function:
func testShowAlert () {let controller = CalculatorController () controller.result = 5 // Create a mock UIWindow to present the merry let window = UIWindow (frame: UIScreen.main.bounds) window.rootViewController = UIViewController () window.makeKeyAndVisible () // Call showAlert () and make certain the alert is presented controller.showAlert () XCTAssertTrue (window.rootViewController? .presentedViewController is UIAlertController) // Dismiss the alert window.rootViewController? .dismiss (alive: true, completion: nil)}It creates an case of theCalculatorController, sets the result belongings to 5, creates a mockUIWindowto present the alert, shoutshowAlert() mapping and so checks if the presented panorama controller is an instance of UIAlertController.
Finally, the trial dismisses the alert by ringdismiss() function on therootViewController. This test verifies that theshowAlert() office stage an alert when the issue holding is set to a non-zero value.
3. Test Asynchronously
The below code is an illustration of an asynchronous trial method using Swift & # 8217; s new async/await syntax. ThetestWebLinkAsyncmethod uses the URLSession API to download the webpage at the specified URL, and verify that the answer is an HTTP 200 OK position code.
func testWebLinkAsync () async throws {// Create a URL for a webpage to download. let url = URL (string: `` https: //bstackdemo.com '')! // Use an asynchronous use to download the webpage. let dataAndResponse: (data: Data, response: URLResponse) = try await URLSession.shared.data (from: url, delegate: nil) // Assert that the actual response jibe the expected answer. let httpResponse = try XCTUnwrap (dataAndResponse.response as? HTTPURLResponse, `` Expected an HTTPURLResponse. '') XCTAssertEqual (httpResponse.statusCode, 200, `` Expected a 200 OK response. '')}- asynckeyword indicates that the method is an asynchronous function that can suspend and resume its performance.throwskeyword indicates that the method can throw an error.
- The first line make a URL object for the webpage to download. Theawaitkeyword suspend the execution of the method until the download operation is consummate.
- The URLSession.shared.data (from: delegate:)method initiates an asynchronous download of the webpage, render both the download datum and the URL answer.
- The XCTUnwrapfunction attempts to divulge the response as an HTTPURLResponse object. If the unwrapping fails, it throws an error with the specified message.
- The XCTAssertEqualfunction affirm that the response status code is 200 OK. If the assertion fails, it throws an error with the specified message.
Note that to use async/await syntax in Xcode, you must be habituate a version of Swift that supports it (currently Swift 5.5 or subsequently). Additionally, the XCTest framework has added support for asynchronous testing with the XCTWaiter API.
For our next test we will prove a function synchronously using postponement and timeout:
func testCalculateSumAsync () {let controller = CalculatorController () controller.firstNumber = `` 2 '' controller.secondNumber = `` 3 '' let prospect = XCTestExpectation (description: `` calculateSum () completes '') DispatchQueue.main.async {controller.calculateSum () XCTAssertEqual (controller.result, 5) expectation.fulfill ()} wait (for: [expectation], timeout: 5.0)}- We make an instance ofCalculatorController, set the values offirstNumber and secondNumber. Then, we use DispatchQueue.main.async to execute the calculateSum function asynchronously.
- Next, we useXCTAssertEqualto verify that the solution property of the controller is indeed 5 after thecalculateSummapping has completed.
- Finally, we useexpectation.fulfill() to indicate to the test framework that the asynchronous trial has completed successfully.
- By using DispatchQueue.main.async and expectation.fulfill(), we can properly essay the deportment of codification that executes asynchronously, ensuring that our tests are comprehensive and accurate.
4. Mock Dependencies
Using mock target to simulate dependencies and sequester the code be tested
- When writing unit tests, it & # 8217; s important to sequester the code being tested from any external dependencies, such as network requests or database operations. One way to achieve this is by using mock objects.
- Mock objects are objects that mimic the behavior of existent aim, but are project specifically for prove purposes. They can be used to simulate dependance and ensure that the code being try is functioning right.
For instance, imagine a category that relies on a web request to find datum. To test this form, you could create a mock network service that return a predefined set of data, rather than relying on a real network request.
Here & # 8217; s an example of how you could use a mock object to test a category :
class MockCalculatorController: CalculatorController {var calculateSumCalled = mistaken nullification func calculateSum () {calculateSumCalled = true result = 5}} func testCalculateSumWithMock () {let controller = MockCalculatorController () controller.firstNumber = `` 2 '' controller.secondNumber = `` 3 '' controller.calculateSum () XCTAssertTrue (controller.calculateSumCalled) XCTAssertEqual (controller.result, 5)}- In this test, we are testing thecalculateSum() method with a mocked object ofCalculatorController.
- We create a subclass ofCalculatorController named MockCalculatorControllerand override thecalculateSum() method.
- In this overridden method, we set thecalculateSumCallediris to true and set the result property to 5.
- We then create an example ofMockCalculatorController, set the values offirstNumber and secondNumber, and callcalculateSum() method on it.
- Finally, we swan that thecalculateSumCalledflag is true and the result place is adequate to 5.
- This test verifies that thecalculateSum() method is working as wait and that the mocked object is right revert the expected value.
It & # 8217; s significant to mark that relying too heavily on mock objects can also be problematic. If the mock aim doesn & # 8217; t accurately mimic the doings of the real addiction, the tests may not catch any errors that pass when using the real dependency.
Strike a balance between using mock objects to isolate code and examine the existent dependencies to guarantee their functionality.
5. Test User Interface
are separate from unit tests, when initialized the default UI test class has the following code:
BrowserStackDemoUITests /BrowserStackDemoUITests.swift
importation XCTest final class BrowserStackDemoUITests: XCTestCase {override func setUpWithError () throws {// Put setup code here. This method is called before the invocation of each test method in the course. // In UI tests it is usually best to stop immediately when a failure happen. continueAfterFailure = false // In UI exam it ’ s important to set the initial province - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.} override func tearDownWithError () throws {// Put teardown code hither. This method is called after the invocation of each test method in the class.} func testExample () throws {// UI tests must launch the application that they screen. let app = XCUIApplication () app.launch () // Use XCTAssert and related map to verify your tests create the correct results.} func testLaunchPerformance () throws {if # available (macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {// This measures how long it guide to launch your application. quantity (metric: [XCTApplicationLaunchMetric ()]) {XCUIApplication () .launch ()}}}}Running the code will found a simulator and exam for app UI performance.
In this grade, you can create extra tryout methods to test different constituent of the application & # 8217; s user interface. To interact with the exploiter interface, you can use the XCUIElement class to detect and interact with different elements on the screen, such as buttons, textbook fields, and table.
is a powerful framework for automate UI essay in iOS application. It provides a wide-eyed range of capabilities for testing different app types, use cases, and twist weather.
Here are some representative:
- Test different app character: XCUITest can be use to test any type of iOS app, including those that use UIKit, SwiftUI, or other frameworks. It can also test coating that use third-party libraries and APIs.
- Test different use case: XCUITest can simulate user interactions with the application, such as tapping button, scroll through lists, entering schoolbook, and more. This do quiz a wide range of use cases potential, from simple to complex.
- Test different gimmick conditions: XCUITest can simulate different device conditions, such as screen sizing, orientations, and languages. This makes it potential to essay how the application behaves in different environs without the need for physical devices.
Read More:
Running Unit Tests from Xcode
Step 1. Product & gt; Test: Use the test bidding to run all tests in a labor.
Step 2. Using the test triangles: Click on the rhombus shape icon on the left-hand side of the code editor to run all tests in the file. Click on the triangle soma icon next to a specific test method to run that test only.
Step 3. Re-run the latest test: Press “ Command + U ” to run the last test.
Step 4. Run a combination of examination: Click on the Test navigator, select multiple tests, and chatter the Run button.
Step 5. Applying filters in the test navigator: Use the hunt bar in the Test navigator to dribble trial cases and test methods based on keywords.
Step 6. Code coverage: Show test coverage for each file by enabling the sidebar in the code editor and selecting the Code Coverage option.
After enable, you should be able to see the code coverage in your editor after running tests.
Interpreting and understanding trial results
A dark-green checkmark means the test passed, while a red X intend the exam failed.
Failed tests are highlighted in red and show error messages describing what went wrong.
The console log furnish farther detail and trace in case of errors.
Debugging failed unit tests
Debugging involves finding the root cause of a bug in your code. By stepping through the code, inspect variables and watching them alteration, you can sequestrate where the bug is happening.
The Xcode debugger permit you to control performance of your code, monitor variables, pause execution, and position variables in code and the variable viewer. The call stack helps you navigate related codification, and you can evaluate expressions in the console to see more information about variables.
Use the Xcode debugger to insulate bugs in your codification by stepping through it and inspecting variables. Customize what Xcode displays by choosing Behaviors & gt; Running. Use the debug bar to check your app ’ s execution.
Hover over variables in your germ code to consider their values, or use the variable looker to name variable available in the current performance setting. Use the console to interact with the debugger direct and evaluate expressions. Select a line in the yell stack to see the root and variables.
Unit Testing Integration with CI
has become essential to modern software development workflows. It aid developers automate the building, testing, and deployment of code alteration, leading to faster delivery of high-quality software.
One crucial aspect of CI is integrating unit testing into the process to catch issues early and ensure code lineament across local, test and production environs.
- Running Tests in Isolation: When mix unit exam with CI, running tests in isolation is essential to prevent international constituent from affect test results. This includes separating unit tests from integration exam, running examination on a separate server, and debar dependance on other systems.
- Using the Same Environment as Production: Another best recitation for integrating unit tests with CI is to use the same environment and data as production. This means setting up a identical to the production surroundings, including hardware, software, and network configurations. Doing this helps to ensure that your code will work seamlessly in product, cut the chances of unexpected number.
- Creating a Comprehensive Test Plan: Creating a is essential for effective unit examination.
This plan should include to see critical functionality is working correctly and fixation tests to control that new code change don & # 8217; t break existent functionality. The test plan should also continue edge cases and other scenario specific to your application.
BrowserStack cloud infrastructure offers a wide range of creature for machine-driven testing, including functional examination, ocular testing, and performance testing.
It can test applications across various operating system, browser, and devices, do it an splendid fit for CI. Developers can assure that their application work seamlessly across different environment and configurations, reducing the endangerment of unexpected number in production.
Good Practices for publish Effective Unit Tests
As we reach the end of this iOS unit testing tutorial, hither are the top 7 best practices:
- Write testable code: Good unit tests are only possible if the code you are screen is testable. To create code testable, it should be modular, slackly coupled, and postdate theSingle Responsibility Principle (SRP).
- Create a separate test target: A separate test target should contain your test classes. This allow you to run your test independently of the app target and helps to ensure that your tests do not accidentally change your application data.
- Keep test methods small and focused: Each trial method should quiz only one thing and focus on a specific aspect of the code. Keeping examination small and focused makes composition, reading, and maintaining them easier.
- Use arrange, act, and assert (AAA) pattern: AAA patternis a common way to structure unit tests. In this pattern, the test is divided into three parts: arrange, act, and assert. The arrange phase sets up the test data and dependencies, the act stage ring the method be tested, and the assert phase verifies the expected results.
- Use descriptive method name: The method name should indicate what the test is try. This makes it easier to interpret what the test is do when it miscarry and helps identify which tests need to be run when you are debugging.
- Test coverage: Use instrument to ensure that your examination continue all the codification way. Aim to achieve as high codification coverage as potential.
- Continuous desegregation: Integrate unit tests with a CI workflow to automate the examination process and ensure that tests are run consistently. This can help to catch bugs early in the development process.
On This Page
- Importance of iOS Unit Testing
- Key Benefits of iOS Unit Testing
- What can you test with Unit Testing?
- Getting Started with Development on App Store
- Figuring out What to Test in iOS App Unit Testing
- Configuring Xcode for iOS App Unit Testing
- Writing iOS Unit Tests
- Running Unit Tests from Xcode
- Unit Testing Integration with CI
- Best Practices for writing Effective Unit Tests
# Ask-and-Contributeabout this topic with our Discord community.
Related Guides
Automate This With SUSA
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts needed.
Try SUSA FreeTest Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free