## What is unit test?

Unit test is basically just a test at the unit level.

Your project will have multiple classes. Each class will have multiple methods. Each method will have multiple cases. And it’s in those cases that we are at the unit level.

A unit test will test for a specific case in a method. It usually has 4 steps:

1. Setup:
• This is where you initialize the class you want to test
2. Execution:
• Call method on the class or instance of the class
3. Expectation:
• Set some expectations for the outcome
4. Cleanup: (optional)
• Clean up anything that may affect other subsequent tests

Let’s look at some example unit tests here (in pseudo code):

Test the shoot method on Gun class:

• Case 1: if it has bullet(s), the gun CAN shoot
• Case 2: if it has no bullet, the gun CANNOT shoot

Test the reload method on Gun class:

After we finish writing unit tests for all cases in all methods of the Gun class, we can say that the Gun class is fully tested. All the edge cases are covered and we would have the confidence that this Gun class should work as expected.

## But that’s just a bunch of pseudo code. How does we translate it into iOS?

Xcode does provide a way to write unit tests natively through the XCTestCase class. It provides a variety of assertion methods to help us describe our expectation for the test. Let’s dive in and see what it looks like.

First, add a new file to your test target. (if your project name is MyAwesomeProject, then your test target’s name would be MyAwesomeProjectTests)

Choose the Unit Test Case Class template > Next

Make sure you subclass from XCTestCase.

Originally, your class will look like this:

For simplicity, we’ll remove everything and just put our single test there. Notice that your test method MUST begin with the prefix test. (Ex: testSomething, testFirst, testTheWorld)

Let’s write our first expectation.

This reads as expect the boolean expression (1 + 1 == 2) to be true or expect 1 + 1 to equal to 2. When you run this test (⌘ + U), it should pass.

But when you change it to:

This will fail.

When the test fails, we know exactly which line it is located but we don’t know why it failed, we only see a general statement XCTAssertTrue failed, which is not very useful. Let’s fix that by adding another argument for error message.

Now it looks better when it fails.

Besides XCTAssert, there are some other methods you can use for assertion, such as:

• XCTAssertTrue(booleanExpression, errorMessage): pass when booleanExpression is true, otherwise fail with errorMessage. This one is equipvalent to XCTAssert.

• XCTAssertFalse(booleanExpression, errorMessage): pass when booleanExpression is false, otherwise fail with errorMessage.

• XCTAssertNil(object, errorMessage): pass when object is nil, otherwise fail with errorMessage.

• XCTAssertEqual(object1, object2, errorMessage): pass when object1 is equal to object2, otherwise fail with errorMessage.

• XCTAssertThrowsError(expression, errorMessage, errorHandler): pass when expression throws exception while evaluated, otherwise fail with errorMessage. We can also use the errorHandler to assert for the exception thrown. For example:

This is just some methods that I use often. For the full list, please refer to Apple documenation.

Let’s write real unit tests for the Gun example we talked about earlier.

Test the shoot method on Gun class:

• Case 1: Gun CAN shoot if it has bullet(s).
• Case 2: Gun CANNOT shoot if it has no bullet.

Both of these 2 tests will fail because we haven’t implemented the Gun class yet. Let’s go ahead and do it.

Add a new file called Gun.swift inside your main target (not inside the test target). We will do a very simple implementation here:

Go to the test class (MyNativeTests.swift) and import your main target. Without this step, all of your classes in the main target won’t be visible to the tests.

The @testable means that you don’t need to declare your classes and methods as public anymore. All of them will be visible in the test target eventually.

Now when you run the tests (⌘ + U), they should all pass. Here is the test class at this point:

There is still the reload method to test but I guess you can easily do it on your own since it’s quite similar to what we just did.

### Wrap up

Today we learnt what a unit test is and how to write it properly in iOS using XCTestCase. We also learnt how to test an object at the unit level (test each case in each method, test all methods in the class).

Although XCTestCase is simple and quite straightforward to use, it might get really tedious as your test becomes more complicated. On the next post, we’ll discover some of XCTestCase’s problems and how we can solve it using Behaviour Driven Development.

## Subscribe to my blog

If you think this blog is useful, please subscribe to get notifications on my new posts.