Unit Test of Private IBOutlet in UIViewController

Yuya Horita
4 min readJul 9, 2019

--

Introduction

UIViewController is a key part of iOS application. If you implement a ViewController with storyboard/xib, you use @IBOutlet attribute.

Which access level do you give those variables? public , internal or private . I often use private . It makes codes concealed and independent from outside. This is good, but may decrease testability of ViewController. Because private properties are not accessible. Properties with internal can be accessed by using @testable import , but not for private .

In this article, I’ll show small tips of testing private properties.

Mirror API

I introduce Mirror API.

Mirror: A representation of the substructure and display style of an instance of any type.

A mirror describes the parts that make up a particular instance, such as the instance’s stored properties, collection or tuple elements, or its active enumeration case.

The above description is quoted from Apple document. It shows we can get stored properties via mirror.

Let’s think the following type.

Create movie instance and set it to movie variable with Any type.

Next, investigate what the type is

Of course, the type is Movie and the instance is interpreted as struct .

Mirror also enables us to inspect stored properties by children property.

Mirror.Children is just a typealias of AnyCollection<Mirror.Child> and Mirror.Child is just a typealias of (label: String?, value: Any) .

Try looping children ,

can get stored property information regardless of the access level even if it is private . label is the name of stored property variable and the value is the instance of it.

Can access each property by this function.

The MirrorPath type appeared out of nowhere is a Swift protocol.

Do not declare new conformances to this protocol; they will not work as expected. 😱

But, don’t worry. String and Int are conformed to this protocol

So, can get instances of movie’s properties like the following.

Unit Test of Private IBOutlet in UIViewController

In the previous section, we knew can get private instances by Mirror. Using the tips, try testing private IBOutlet in UIViewController.

Target ViewController is the following. Layout is configured in Main.storyboard .

In the test module, I defined this common MirrorObject class.

Inheriting this class, define new class. Via this mirror instance, can access private titleLabel in ViewController.

The variable name is used for Mirror.descendant first parameter, so it must be same as the IBOutlet variable name here.

Finally, can test private property of ViewController 🎉 🎉.

The method I described, accessing private property, can be used for application code, but it is risky. Only for test codes, would be helpful. IMO.

--

--

Yuya Horita

Master of Nuclear Physics, CyberAgent, Inc. FRESH LIVE. M3. Software Engineer. Twitter: https://twitter.com/horita_yuya ,GitHub: https://github.com/horita-yuya