Testing Concepts Flashcards
iOS Testing:
What is a unit test and how can you write unit tests for an iOS application?
Unit tests are automated tests that validate a piece of code to make sure it behaves as intended.
When you create a project or a target, Xcode includes a unit test target in the scheme that builds the app. Unit tests are written using Apple’s XCTest framework. To start writing unit tests, we would create a subclass of XCTestCase and define methods that start with test.
For example, if we were on the Swift development team and we wanted to unit test Swift’s joined array method, one of the unit tests could look like this:
func testJoinedTwoWords() throws {
let words = [“Hello”, “world”]
let result = words.joined(separator: “ “)
XCTAssertEqual(result, “Hello world”)
}
iOS Testing:
What is code coverage and when is it useful?
Code coverage indicates the percentage of the code that was executed when running the corresponding unit tests. We can enable code coverage in the target’s scheme settings.
While code coverage doesn’t tell us anything about the quality of the unit tests, it is a great way to identify code paths that aren’t tested yet.
iOS Testing:
What is the Given, When, Then style regarding unit tests?
The Given, When, Then style is commonly used to make tests easier to read. The essential idea is to structure the unit test into three parts:
The given part setups the pre-conditions of the test
The when part executes the actions we want to test
The then part validates the outcome
In our example above, we can directly apply this technique.
func testJoinedTwoWords() throws { // Given let words = ["Hello", "world"]
// When let result = words.joined(separator: " ")
// Then XCTAssertEqual(result, "Hello world") }
iOS Testing:
When using the XCTest framework, when would we use the setUp() and tearDown() methods?
To reuse data in multiple test methods, we can define them as instance variables in our test case class. We can then use the setUp() method to set up the initial state for each test method and the tearDown() method to clean up after the test is complete.
iOS Testing:
What are mocks and stubs when it comes to writing tests?
Mocking and stubbing are key techniques to manage dependencies and isolate a specific behaviour of the tested object. Replacing the dependencies of the tested object with mocked or stubbed objects makes it more easily to assert and verify outcomes in our tests. Mocks and stubs are testing helpers and not suitable for production.
iOS Testing:
What are performance tests and how can you write performance tests for an iOS application?
With performance tests, we can measure how fast our code runs. The tests also help us identify performance changes as our code base evolves.
To measure how long some code takes to execute we can use XCTest’s measure method.
func testNextMovePerformance() throws { measure { brain.calculateNextMove() } }
On the first run, Xcode establishes a baseline for each performance test and will fail in the future if the performance significantly changes.
iOS Testing:
What is a user interface test and how can you write user interface tests for an iOS application?
User interface tests test the application from the outside, from the user’s point of view. UI testing is a great way to ensure that the app’s UI interactions keep working as expected while the codebase evolves.
Just like with unit testing, we can use the XCTest framework to write UI tests. The approach is different though, because now we are interacting with the app itself and not with the code.
We do that by using the iOS accessibility system. The XCTest framework provides methods to access and interact with the UI elements e.g. via their accessibility identifier.
func testRegister() throws { let app = XCUIApplication() app.launch() app.buttons["registerButton"].tap()
XCTAssertTrue(app.textFields["nameTextField"].exists) XCTAssertTrue(app.textFields["emailTextField"].exists) ... }
iOS Testing:
What is test-driven development (TDD)? What advantages and disadvantages does TDD have in your opinion?
TDD is a development approach where you write a test before implementing the method to pass that test.
This approach mostly leads to better code coverage since testing becomes first priority. If done right, it also leads to a more modularised, structured code. TDD can slow down the development, especially refactoring the code base requires adapting all the tests as well.
iOS Testing:
What is behaviour-driven testing? How would you write behaviour-driven tests in iOS?
In behavior-driven testing, the tests are based on user stories that describe some expected behaviour of the application. Compared to unit tests, behaviour-driven tests are more user- and feature-focused, regardless of implementation details.
For iOS, we can use the third party libraries Quick and Nimble to implement behaviour-driven testing. They allow us to write tests in a way that is closer to our natural language.
describe("a dog") { let dog = Dog()
context("when the dog is playing with the toy") { let toy = Toy() dog.play(with: toy)
it("the toy should not be damaged") { expect{toy.isDamaged}.to(equal(false))) } } }
iOS Testing:
What is snapshot testing and how can you write snapshot tests for an iOS application?
Snapshot tests make sure that the user interface of the app does not change unexpectedly.
A snapshot test takes a snapshot of a UI element and compares it to a reference snapshot that was stored before. The test will fail if the two snapshots do not match. Either the change is unexpected or the reference snapshot needs to be updated to the new version of the UI element.
There is no native support for snapshot testing in iOS, but there are some third-party libraries like iOSSnapshotTestCase or SnapshotTesting that can be used.