Skip to main content

7 questions tagged with "Testing"

Testing tag description

View All Tags

How would we test the performance of a method in our tests?

2 min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 馃敆 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

The XCTest framework includes a measure() function for profiling code execution times. We can call this method within our testing target to measure the performance of a block of code:

func testExample() throws {
measure {
sayHelloWorld()
}
}

By default, this method counts the number of seconds it takes to execute a block of code.

To customize the metrics measure() function tracks, we can override defaultPerformanceMetrics[] and specify our own metrics to track.

The measure() function runs the code within the closure ten times and reports the average execution time and standard deviation. These numbers will now serve as the benchmarks for all future runs of this test.

On a subsequent run, if the execution time is within 10% of the benchmark value, the test will pass. Otherwise, the test will fail. This can help us catch performance problems early on in the development process.

If we were to improve the performance of the code we're profiling, we can simply update the baseline measurement, and now all subsequent executions will be compared against this new value.

Xcode saves benchmark numbers into source control which allows them to be standardized across teams.

Finally, the benchmark numbers are device-specific. This ensures that Xcode will not fail the test when the iPhone 6 performs worse than the iPhone 13.

What are the purposes of setUp() and tearDown() in the XCTest framework?

One min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 馃敆 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

Whenever we run tests, we'll often want each test to run independently. More specifically, we want to ensure that each test is executed under identical conditions and the end state of one test doesn't inadvertently influence the start state of another test.

TheXCTestframework provides two functions we canuse to ensure these conditions are met - setUp() and tearDown(). These functions allow us toprepare and clean up all allocations and dependencies before the next test is run.

setUp(): This method is called before each test isinvoked and provides us an opportunity to reset state.

tearDown(): This method is called after every testmethod has finished execution and is used to perform any necessary clean up or releasing of resources.

These functions allow us to reuse data more easily in our tests.

For example, we can create instance variables to represent mock data in our XCTestCase class and then utilize the setUp() method to reset the initialstate of these variables for each test and the tearDown() method to perform any necessarycleanup after the test is completed.

What are UI tests?

2 min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 馃敆 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

User interface tests allow us to test our application鈥檚 behavior from the user鈥檚 perspective. It helps us to ensure that our application鈥檚 UI interactions, animations, and various user flows continue to work correctly as our application evolves.

While unit testing focuses on the inputs and outputs of the functions within our codebase, UI Testing aims to verify user-facing behavior.

To implement UI tests, we will continue to use theXCTestframework.XCTestwill then leverage the iOS Accessibility System to interact with the various UI components specified by the test.

For example, a simple UI test that ensures the correctness of a login form might look like this:

import XCTest

class LoginViewUITest: XCTestCase {
func testUserLogin() {
// Launch app
let app = XCUIApplication()
app.launch()

// Simulate button press
app.buttons["loginButton"].tap()

// Asserts that the Login form is shown correctly
XCTAssertTrue(app.textFields["usernameTextField"].exists)
XCTAssertTrue(app.textFields["passwordTextField"].exists)
}
}

Xcode can also record and automatically create UI tests based on your interactions with theapplication. For most UI tests, you can just hit Record in Xcode, walk through some flow in your application, and then add the automatically generated test to your test suite.

What does Arrange, Act, and Assert mean with respect to unit tests?

One min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 馃敆 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

Arrange, Act, and Assert describe the ideal structure for a unit test.

Firstly, you have to arrange all the necessary inputsand preconditions. Secondly, you perform some action or operation on the object to be tested.And finally, you assert that the expected outcome has occurred.

Here鈥檚 an example:

class EmailValidationTests: XCTestCase {
func testValidEmail() {
// Arrange
let testEmail = "aryaman@digitalbunker.dev"

// Act
let isValidEmail =EmailValidation.validate(testEmail)

// Assert
XCTAssertTrue(isValidEmail)
}

func testInvalidEmail() {
// Arrange
let testEmail = "aryaman@digitalbunker"

// Act
let isValidEmail =EmailValidation.validate(testEmail)

// Assert
XCTAssertFalse(isValidEmail)
}
}

This approach helps improve the readability of your tests and makes the expected behavior obvious.

What is a unit test?

One min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 馃敆 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

A unit test is a type of automated test used to validate the correctness of a piece of code by providing an exhaustive list of inputs and ensuring that the expected outputs are returned.

Xcode provides easy support for writing unit tests by way of theXCTestframework. In our app鈥檚 testing target, we could write a simple test like this and assert that the output from the function call matches our expected output:

func testOnlyEvenNumbersFilter() {
let input = [ 2 , 3 , 4 , 5 , 6 , 7 ]
let onlyEvens = Math.onlyEvens(input)
XCTAssertEqual([ 2 , 4 , 6 ], onlyEvens)
}

Note: When you鈥檙e creating tests in your testing target, the first word of the function name needs to betestin order for Xcode to register itas a unit test.

Unit testing can be a great way to protect our codebase against regressions and is far more scalable than relying on manual testing alone.

What is Snapshot Testing?

One min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 馃敆 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

Snapshot Testing involves comparing the UI of an application against a set of reference images to ensure correctness.

If the difference between the actual UI and the reference image exceeds some custom threshold, the test fails. This is a really convenient way to ensure that there are no unexpected changes or regressions made to the UI of your application.

While UI tests allow us to test the functionality of our application, snapshot tests focus more on verifying that the implementation matches the agreed upon designs. Snapshot Testing is often easier to implement and update than writing traditional UI tests. Plus, it lets you easily verify the application鈥檚 appearance across a variety of device sizes. Lastly, if you change the UI of your application, you鈥檒l be forced to update its corresponding snapshot test which helps ensure your testing suite remains up to date.

Currently, Snapshot Testing is not natively supported through Xcode. However, there are several open-source iOS libraries that enable you to add Snapshot Testing support to your app.

What is Test Driven Development?

2 min read
Ace the iOS Interview
Aryaman Sharda
Sources & Resources

Main Source: 馃敆 Ace the iOS Interview

Additional Sources:

Further Reading:

TL/DR

Test-Driven Development (TDD) is a software development process relying on software requirements first being converted to test cases prior to writing any production code. Then, the correctness of all subsequent development is measured against those tests.

A typical TDD workflow would look like this:

  1. Write a single test for the functionality you intend to build or amend.
  2. Run the test and ensure that it fails (which it should as the functionality is not yet built).
  3. Write just enough code to ensure the test passes.
  4. Refactor the code and perform whatever clean up is necessary (remove duplication, Single Responsibility Principle, etc.)
  5. Rinse and repeat all the while building up new features and tests simultaneously.

This approach is useful in helping reduce the frequency of regressions in your application and in increasing your project鈥檚 code coverage.

Writing these tests early on helps provide documentation about how the app is expected to behave. TDD promotes writing modular and testable code as it forces the developer to think in small units of functionality that can be easily tested.

In discussions of TDD, you may often see it broken down into 3 stages - Red, Green, and Refactor.

Red: Create a unit test that fails.

Green: Write just enough production code to make your test pass.

Refactor: Once your tests are passing, you鈥檙e free to make any changes to your code. This is your opportunity to clean up your implementation and refine your approach.

TDD only focuses on unit tests and doesn鈥檛 cover UI behavior or integration tests, so it鈥檚 often paired with additional testing paradigms.