Skip to content

Unit testing in XCode

Ramon Goncalves da Silva edited this page May 5, 2017 · 10 revisions

Extensive Unit tests have been done to ensure quality. Unit tests are supported in the native IDE for iOS: Xcode. To setup Unit tests in Xcode, one should go to Xcode Test Navigator, and click on the "+" sign, and then on "New Unit Test Target...".

Then, one should name the test file, choose its specifications, and click "Ok".

Now the first thing to be done before writing any test methods is to write @testable import <NAME_OF_THE_PROJECT>, which in this case would be: @testable import MazeRunner. This allows the test class, which is in a different module, to import all classes from the target specified in <NAME_OF_THE_PROJECT>, and therefore import all project's classes.

Once the class has been created, since it inherits from XCTestCase, two methods are automatically inherited: override func setUp() and override func tearDown(). These methods are meant for initialization and destruction of any instances used in tests, the SUT (System Under Test). This means that any test will call setUp() before calling its own methods and call tearDown() after its own execution. Therefore, these methods would be similar to a constructor and destructor if single test methods were classes.

A good practice in TDD (Test-Driven Development) is to create the SUT in setUp() and release it in tearDown(), to ensure a clean state for every test. The latter, is, unfortunately, still not practiced by all developers. Please refer to http://qualitycoding.org/teardown/ to know more about it. To create unit tests, one must write functions/methods that begin with the word "test". Therefore all of these are methods the IDE is going to recognize as test methods and that thus are going to be run when executing tests: func test(), func testExample(), func testingAnything(), etc.

To write a Unit test, the SUT should be declared in the class scope. It should be initialized in setUp(), and released in TearDown(). Inside the test method, SUT's methods and instances are accessed to ensure that its methods produce the expected outcome. This is done through assertion methods like XCAssertTrue(expression:Bool), XCAssertFalse(expression:Bool), XCTAssertEqual(expression1: [Equatable], expression2: [Equatable]), XCAssertNil(expression: Any?), etc. A string can also be passed as an additional parameter in all these XCAssert functions to print a message in case the test fails. An example of a real implementation can be found below:

Unit tests have still somewhat of a limited scope, and for this reason, workarounds like Mock objects or Studs are used. It is important to mention that both Unit and UI test methods should be independently from others, so that a failure in one test cannot cause another test to fail. In this way, developing tests to be independent, one can ensure that a failure of a test is related to only a single hypothesis, i.e, a SUT's specific method or variable is wrong.

Finally, to run a single test, press on the play button next to its name. To run all tests in the project, press Cmd+U or press the "Run button" (Play symbol) on the top left corner, and a menu will open. Select "Test" (Screwdriver symbol) and click on it.

Tests will then run. If a test succeeds, it will get a green checkmark. Otherwise, a red X will appear next to it, indicating it failed. If all of them pass, the overall test suite succeeded, and a "Tests succeeded" figure will appear.

If at least one of them fail, the overall test suite failed and a "Tests failed" will appear.

The Pipeline

Radiators

Clone this wiki locally