Unit testing collection and table view cell outlets

This is the scenario (I hope a picture is really worth a thousand words):

Screen Shot 2015-12-29 at 11.17.07 AM

This is a very simple cell, with just two outlets, a UILabel and a UIImageView. I would usually build cells this simple programatically, but in this case I was going after something very quick, so I decided to take the opportunity to improve my IB kung fu.

Warning! Read this!

There is an important precondition to this post: the project I’m working on does not use Storyboards, and does not use xibs to declare the layout of view controllers. So, the cell xib is completely isolated!

Moving on

This is the cell in Interface Builder:

Screen Shot 2015-12-29 at 11.17.22 AM

Nothing fancy: a vertical UIStackView that covers the whole cell.

Incoming context switch!

Pardon the deviation, but this is how I like to populate cells lately:

Why on earth I don’t populate the outlets in the collection/tableview datasource? Well, I feel like letting the actual cell (in this case a subclass of UICollectionViewCell) take care of populating its own UI is the way to go. It provides better encapsulation, and better separation of concerns. The cell takes care of the UI, and the datasource only takes care of dequeuing a cell and providing it with a data object. Single responsibility principle FTW!

Back to unit tests

So, now I want to unit test that cell. Which means that I want to test that my expectation about the behaviour of that cell are fulfilled.

What is my expectation? I expect that, if I pass it an Item with a given title, the cell label will contain that Item’s title.

It might sound like something obvious and not worth testing, but that’s the whole point of unit testing: being able to break expectations down into small chunks, almost trivial chunks, that don’t require too much context to be tested. That way, tests are easy to understand, and make great documentation about the behaviour of the whole system with a level of details very difficult to achieve by other means.

Load all the things!

The issue here is that I need to load a xib within the testing bundle. So, the first thing I need to do is add the xib to the testing bundle:

Screen Shot 2015-12-29 at 11.29.28 AM

That’s something I don’t really like, but I am afraid it is impossible to avoid.

Now, there is one more thing to do. Make sure to specify, in Interface Builder, the Module that the cell’s custom class belongs to:

Screen Shot 2015-12-29 at 11.30.23 AM

This step is important. If you leave the default value, Xcode will try to find FeaturedCell in the testing bundle.

So, now, in your unit test class, you need to load the xib (the one in the testing bundle), and extract its first element, casting it to your custom class, qualified with the module name. Qualifying the module name is important as well, it will tell the test to look for your class in your module, not in the tests bundle:

And, finally, test your expectation

Now, it is just a matter of testing your actual expectation, which in my case was that setting an instance of Item as the cell’s data property, will assign the Item’s title to the cell’s titleLabel.


One Reply to “Unit testing collection and table view cell outlets”

Leave a Reply

Your email address will not be published. Required fields are marked *