In the previous section, we added a struct to hold information about the location. We will now add tests to make sure that Location
has the required properties and initializer.
The tests could be added to ToDoItemTests
, but they are easier to maintain when the test classes mirror the implementation classes/structs. So, we need a new test case class.
Open Project Navigator, select the ToDoTests
group, and add a unit test case class with the name LocationTests
. Make sure that you go to iOS | Source | Unit Test Case Class because we want to test the iOS code and Xcode sometimes navigates to OS X | Source. Choose to store the file in the Model
folder we created previously.
Set up the editor to show LocationTests.swift
on the left-hand side and Location.swift
in the Assistant Editor on the right-hand side. In the test class, add @testable import ToDo
, and remove the testExample()
and testPerformanceExample()
template tests.
To drive the addition of a coordinate
property, we need a failing test. Add the following test to LocationTests
:
func testInit_ShouldSetNameAndCoordinate() { let testCoordinate = CLLocationCoordinate2D(latitude: 1, longitude: 2) let location = Location(name: "", coordinate: testCoordinate) XCTAssertEqual(location.coordinate?.latitude, testCoordinate.latitude, "Initializer should set latitude") XCTAssertEqual(location.coordinate?.longitude, testCoordinate.longitude, "Initializer should set longitude") }
First, we create a coordinate and use it to create an instance of Location
. Then, we assert that the latitude and longitude of the location
coordinate are set to the correct values. We use the values 1
and 2
in the initializer of CLLocationCoordinate2D
because it has also an initializer that takes no arguments (CLLocationCoordinate2D()
) and sets the longitude and latitude to zero. We need to make sure in the test that the initializer of Location
assigns the coordinate
argument to its property.
The test does not compile because CLLocationCoordinate2D
is an unresolved identifier. We need to import CoreLocation
in LocationTests.swift
:
import XCTest
@testable import ToDo
import CoreLocation
The test still does not compile because Location
does not have a coordinate
property yet. Similar to ToDoItem
, we would like to have a short initializer for locations that only have a name
argument. Therefore, we need to implement the initializer ourselves and cannot use the one provided by Swift. Replace the contents of Location.swift
with the following lines of code:
import CoreLocation struct Location { let name: String let coordinate: CLLocationCoordinate2D? init(name: String, coordinate: CLLocationCoordinate2D? = nil) { self.name = "" self.coordinate = coordinate } }
Now run the tests. All the tests pass.
Note that we have intentionally set the name in the initializer to an empty string. This is the easiest implementation that makes the tests pass. But it is clearly not what we want. The initializer should set name
of the location to the value in the name
argument. So, we need another test to make sure that name
is set correctly.
Add the following test to LocationTests
:
func testInit_ShouldSetName() { let location = Location(name: "Test name") XCTAssertEqual(location.name, "Test name", "Initializer should set the name") }
Run the test to make sure it fails. To make the test pass, change self.name = ""
in the initializer of Location
to self.name = name
. Run the tests again to check whether they all pass now. There is nothing to refactor in the tests and implementation. Let's move on.