Unit tests best practices in Xcode and Swift – onlinecode
In this post we will give you information about Unit tests best practices in Xcode and Swift – onlinecode. Hear we will give you detail about Unit tests best practices in Xcode and Swift – onlinecodeAnd how to use it also give you demo for it if it is necessary.
Writing unit tests is just as important as writing your application code. Unit tests are oftentimes the first to be skipped when a deadline is coming close although exactly this might slow down the project in the end. You’ll thank your future self once your project has grown and you’ve written a lot of unit tests to cover most of your apps logic.
This will not cover the testing of memory leaks or writing UI tests for share extensions but will mainly focus on writing better unit tests. I’ll also share my best practices which helped me to develop better and more stable apps.
Once you’ve written your tests it’s time to run them. With the following tips, this has become just a bit more productive.
What is unit testing?
Unit tests are automated tests that run and validate a piece of code (known as the “unit”) to make sure it behaves as intended and meets its design.
Unit tests have their own target in Xcode and are written using the XCTest framework. A subclass of XCTestCase
contains test methods to run in which only the methods starting with “test” will be parsed by Xcode and available to run.
/// A simple struct containing a list of users.
struct UsersViewModel {
let users: [String]
var hasUsers: Bool {
return !users.isEmpty
}
}
/// A test case to validate our logic inside the 'UsersViewModel'.
final class UsersViewModelTests: XCTestCase {
/// It should correctly reflect whether it has users.
func testHasUsers() {
let viewModel = UsersViewModel(users: ["Antoine", "Jaap", "Lady"])
XCTAssertTrue(viewModel.hasUsers)
}
}
Your mindset when writing unit tests
Your mindset is a great starting point for writing quality unit tests. With a few basic principles, you make sure to be productive, retain focus, and write the tests your application needs the most.
Your test code is just as important as your application code
Before we dive into actual practical tips I first want to mention an important mindset. Just like when writing your application code you should try and do your best to write quality code for tests.
Think about reusing code, using protocols, defining properties if they’re used in multiple tests and make sure your tests clean up any created data. This will make your unit tests easier to maintain and prevents flaky and weirdly failing tests.
100% code coverage should not be your target
Although it’s a target for plenty, 100% coverage should not be your main goal when writing tests. Make sure to test at least your most important business logic at first as this is already a great start. Reaching 100% can be quite time consuming while the benefits are not always that big. In fact, it might take a lot of effort to even reach 100%.
On top of that, 100% coverage can be quite misleading. The above unit test example has 100% coverage as it reached all methods. However, it did not test all scenarios as it only tested with a non-empty array while there could also be a scenario with an empty array in which the hasUsers
property should return false.
You can enable test coverage from the scheme settings window. This window can be opened by going into Product ➞ Scheme ➞ Edit Scheme
.
Write a test before fixing a bug
It’s tempting to jump onto a bug and fix it as soon as possible. Although this is great, it would be even better if you could prevent the same bug from recurring in the future.
By writing a unit test before fixing the bug you make sure that the same bug is not happening ever again. See it as “Test-Driven Bug Fixing”, also known as TDBF from now on ;-).
Writing unit tests in Swift
Now that you have the right mindset it’s time to actually go over a few tips for writing unit tests in Swift. There are multiple ways to test the same outcome while it does not always give the same feedback when a test fails. The following tips help you write tests that help you as a developer.
Naming test cases and methods
Giving both your test cases and methods a good name helps you to quickly identify a failing test. Also, it helps you to explore whether you’ve already tested a certain scenario or piece of code.
To easily find a test case for a certain class it’s recommended to use the same naming combined with “Tests”. Just like in the above example in which we named UsersViewModelTests
based on the UsersViewModel
naming.
Do not use XCTAssert for everything
The following lines of code all test exactly the same outcome:
func testEmptyListOfUsers() {
let viewModel = UsersViewModel(users: ["Ed", "Edd", "Eddy"])
XCTAssert(viewModel.users.count == 0)
XCTAssertTrue(viewModel.users.count == 0)
XCTAssertEqual(viewModel.users.count, 0)
}
As you can see, the method is using a describing name that tells to test an empty list of users. However, our defined view model is not empty and therefore, all assertions fail.
The results are showing why it’s important to use the right assertion for the type of validation. The XCTAssertEqual
method is giving us way more context on why the assertion failed. This is not only showing in the red errors but also in the console logs which helps you identify failing tests a lot faster.
Setup and Teardown
Parameters used in multiple test methods can be defined as properties in your test case class. You can use the setUp()
method to set up the initial state for each test method and the tearDown()
method to clean up.
Apple has some great documentation on these methods that will help you understand how to use them in the right way.
Tip: You can also add assertions to the setup and tear down methods to make them run for every test.
Throwing methods
Just like when writing application code you can also define a throwing test method. This allows you to make a test fail whenever a method inside the test is throwing an error.
func testDecoding() throws {
/// When the Data initializer is throwing an error, the test will fail.
let jsonData = try Data(contentsOf: URL(string: "user.json")!)
/// The 'XCTAssertNoThrow' can be used to get extra context about the throw
XCTAssertNoThrow(try JSONDecoder().decode(User.self, from: jsonData))
}
The XCTAssertNoThrow
method can be used when the result of the throwing method is not needed in any further execution of the test.
Make sure to check out the opposite XCTAssertThrowsError
method for matching the expecting error type.
Unwrapping optional values
New in Xcode 11 is the XCTUnwrap
method that is best used in a throwing test method as it’s a throwing assertion.
func testFirstNameNotEmpty() throws {
let viewModel = UsersViewModel(users: ["Antoine", "Maaike", "Jaap"])
let firstName = try XCTUnwrap(viewModel.users.first)
XCTAssertFalse(firstName.isEmpty)
}
XCTUnwrap
asserts that an Optional variable’s value is not nil
and returns its value if the assertion succeeds. It prevents you from writing a XCTAssertNotNil
combined with unwrapping or dealing with conditional chaining for the rest of the test code.
Running unit tests in Xcode
Once you’ve written your tests it’s time to run them. With the following tips, this has become just a bit more productive.
Re-run latest test
Re-run your last run test again by using:⌃ Control + ⌥ Option + ⌘ Command + G
.
Run a combination of tests
Select the tests you want to run by using CTRL or SHIFT, right-click and select “Run X Test Methods”.
Applying filters in the test navigator
The filter bar at the bottom of the test navigator allows you to narrow your tests overview.
- Use the search field to search for a specific test based on its name
- Show only tests for the currently selected scheme. This is useful if you have multiple test schemes.
- Only show the failed tests. This will help you to quickly find which test has failed.
Enable coverage in the sidebar
Showing the test iteration count shows you whether a certain piece of code is hit during the last run test.
It shows the number of iterations (18 in the above example) and a piece of code turns green when it has been reached. When a piece of code is red it means that it was not covered during the last run tests.
Conclusion
As you can see there is a lot you can do to make writing unit tests a lot easier. Change your mindset, use the right setup and do not use XCTAssert
everywhere.
Thanks!
Hope this code and post will helped you for implement Unit tests best practices in Xcode and Swift – onlinecode. if you need any help or any feedback give it in comment section or you have good idea about this post you can give it comment section. Your comment will help us for help you more and improve us. we will give you this type of more interesting post in featured also so, For more interesting post and code Keep reading our blogs