visit
Recently I conducted several tech interviews and noticed one curious thing. More and more engineers (even middle and seniors) neglect writing tests. They were great candidates, but they didn’t write tests at all. So, let this article be here just for those who need to start writing tests right now.
In your existing project, we need to create a new target — Unit Testing Bundle.
Name your product. A target to be tested should be your app or framework.
If you don’t see your target in the list of targets, then we need to add it manually using the manage targets option.
When you open a file with the test, you will see XCTestCase
template with a few methods. We need only testExample()
. Let’s run it using a rectangle on the left side of this method.
You will see a green checkmark. Your console log will be filled with information about when the test started, how a lot it takes, and so on. But let’s open Test navigator using CMD + 6. You will see the hierarchy of tests and the same green checkmarks.
Green checkmarks mean — your tests are passed. Let’s make our own now.
You testExample()
method let’s add a following code and run it using triangle.
func testExample() throws {
let expr1 = "expression 1"
let expr2 = expr1
XCTAssertEqual(expr1, expr2, "Expressions are equal")
}
In this implementation, we used a specific assertion which is a part of XCTest
framework. Let’s try another example. For that, you can create testExample2()
.
func testExample2() throws {
let expr1 = "expression 1"
let expr2 = "expression 2"
XCTAssertNotEqual(expr1, expr2, "Expressions are not equal")
}
As you can see XCTest framework provides a lot of asserts for all your general test cases:
// Bool assert TRUE
XCTAssertTrue(expression, "description")
// Bool assert FALSE
XCTAssertFalse(expression, "description")
// Assert that expression is nil
XCTAssertNil(expression, "description")
// Assert that expression is NOT nil
XCTAssertNotNil(expression, "description")
// Assert that an expression is not nil and returns the unwrapped value
XCTUnwrap(expression, "description")
// Asserts that two expressons have the same value or not
XCTAssertEqual(expr1, expr2, "description")
XCTAssertNotEqual(expr1, expr2, "description")
// expr1 > expr2
XCTAssertGreaterThat(expr1, expr2, "description")
// expr1 < expr2
XCTAssertLessThat(expr1, expr2, "description")
// expr1 <= expr2
XCTAssertLessThanOrEqual(expr1, expr2, "description")
// Asserts taht two expressions have the same value within a certain accuracy
XCTAssertEqualWithAccuracy(expr1, expr2, accuracy, "description")
// Asserts that two floating-point values are equal within a specified accuracy.
XCTAssertEqual(49.2827, 49.2826, accuracy: 0.001)
struct SignUpFormModel {
let firstName: String
let lastName: String
let email: String
let password: String
let repeatPassword: String
}
extension SignUpFormModel {
func isValidEmailFormat() -> Bool {
return email.contains("@") && email.contains(".")
}
}
testSignUpFormModel_WhenCreated_EmailShouldHaveValidFormat()
test<Subject><Condition Or State Change><Expected Result>()
The name starts with test — it’s important to start from this word, otherwise, XCTest won’t recognize your methods (you won’t see this triangle icon). Other parts describe your test almost in detail. So, if you will make yourself keep using this naming format then your colleagues sooner or later will say thank you in some time.
func testSignUpFormModel_WhenCreated_EmailShouldHaveValidFormat() {
// Arrange (GIVEN)
let firstName = "Maksim"
let lastName = "Kalik"
let email = "[email protected]"
let password = "qwerty123"
let repeatPassword = "qwerty123"
let signUpFormModel = SignUpFormModel(
firstName: firstName,
lastName: lastName,
email: email,
password: password,
repeatPassword: repeatPassword
)
// Act (WHEN)
let isEmailFormatValid = signUpFormModel.isValidEmailFormat()
// Assert (THEN)
XCTAssertTrue(isEmailFormatValid, "Provided valid email address does not have a valid format")
}