The very first obstacle to writing Unit Tests in Swift is access controls! Since the Test Target is different from you Application Target, the files from your application, which are internal to your application target, are not available to your test target.
Fighting Access Controls
There are two ways to make your Swift application classes available to the test target:
1. Make your application classes public – this includes every variable, constant, and function you want to test
2. Add your application Swift file to your Test target. This is pretty simple to do. Just open the Utilities pane and check your application’s Test Target Membership checkbox. Thanks Andrew Bancroft for the tip!
I personally prefer adding my file to the test application target (option #2). My guess is that Apple will fix this issue eventually – by allowing the test target to access the application target, so it seems much easier and safer to add my files to the test target than exposing my functions and variables publicly and eventually having to delete all the public keywords once Apple fixes the test target issue.
The first option of making your functions and variables public would work better if you’re building a framework (which has to have a public interface).
The next confusing issue is initializing objects to test in your Swift unit test, since there is no init method you can override in XCTestCase to set up all your constants and variables.
I’m going to use my Seinfeld Quotes app as an example. Let’s say I want to test my Quote object.
I have a class method that generates all my Quotes, and returns an array of Quote objects. I can create an array of Quote objects variable in my tests, and that variable will be re-calculated for every single test that is being run!
Here is the testing I used to make sure this was the case:
Tests are run in alphabetical order. The cool thing is that removing all the quotes in testAA (which is run first), does not impact the count of Quotes in test AB, and adding an additional quote in testAB has no impact the number of Quotes counted in testAC!
This also works great for constants with variable properties:
So just go ahead an set up your test objects at the top of your test file. They will be re-configured in between tests!
Note: I’ll be updating this section to make it clearer very soon. Meanwhile, take a look (and join) our discussion on Twitter here.
UPDATE: Here is a better way to test optionals from Apple.
Let’s say your object has a few optional variables that need testing – in my case I made my Quote object variables content and scenario optional. While unwrapping optionals is definitely the way to go in the rest of your application, I started to force unwrap them for testing.
The reason is that I want my tests to run regardless of whether the optional value is there or not:
In the above scenario, I want my test to fail if the quote content is not set when I explicitly set it in my test! So force unwrapping the optional is the way to go with testing optional values in my opinion:
Have you tried unit testing in Swift yet? Let me know if you have any tips or tricks in the comments!