Electric transmission tower — Photo by Alina Grubnyak on Unsplash

Is everything connected?

Using Mirror to test references in Swift

Giovani Pereira
Published in
6 min readAug 26, 2020

--

Have you ever had a bug that the solution was just setting a delegate? Or an entire feature that broke because a single reference was not being set correctly? This is an everyday issue of everybody, but we could prevent thesm with tests covering our references. But… how?

If you work with Swift in larger projects, we are probably talking about apps written with architectures a little more complex than the old MVC. And your architecture could be any fancy group of letters like: MVVM, VIP, VIPER, MVMC, etc.

More complex architectures are subjected to more complex bugs. Here, on iFood, we use a Clean Swift based architecture, the VIP, and we've had bugs being solved with simply adjusting a missing reference, or injecting a dependency correctly. But these issues can be really hard to find, because looking into your code, there are no warnings and the flow seems to be correct.

Diagram of a VIP scene. The dashed lines represent weak references between the components

Our View represents the layer of the UIViewController and the displayed UIView, it's the layer that handles the direct user interaction. Then, the Interactor contains all of our business logic, and the Presenter all of the presentation logic.

The reference from the Presenter to the ViewController is weak, to prevent a retain-cycle, and the same applies to the reference from the Router to the ViewController. And everything is bonded using protocols — to increase our testability.

This represents a single scene, and every time we want to create a new one we have an object responsible for instancing and linking everything, and we call it: the Creator.

A simple Creator

The Creator's responsibility is to center the creation of our scene and to guarantee that everything is connected properly. Let's dive into an example:

We could totally write a test to check if our Creator returns the expected ViewController type. It would be a valid test, but… I would not ensure that all the components on the scene are attatched correctly.

Finding properties with refelction

Essentially, we want to make sure that our ViewController has a reference the Interactor, and this Interactor has the expected type (because since the reference is made using a protocol we could have multiple implementations, SceneAInteractorinstead ofSceneBInteractor), and the Interactor has a reference to the right Presenter… and so on until all of our references are covered.

The first issue is that we do not have a reference to the Interactor or the Presenter when we create the scene, we just have a ViewController. And even worse, most of these properties are private, so we can't really access them directly from the ViewController.

That's where the Mirror comes into play.

The Mirror, actually, represents a very common feature in programming languages called Reflection, which allows us to inspect and work over the content of an object in runtime. Its a struct that reflects an object and gives information about its composition: properties, tuples, enums, etc. Here's and example:

The Mirror struct has a property called children which is a collection of tuples (label: Optional<String>, value: Any) where label is the name of the property and value well… its value!

If we take a better look into the code right above, when we access the first item of this collection we can see that the label is a "x", which is the same name we gave to it on the code, and its value isInt(21). We can use these informations to iterate over the children, using both the label and the value to find whathever we are looking for.

What is nice about the Mirror is that it doesn't matter the visibility of the properties: internal, open, public, private… all of them will be reflected on the struct.

Reflection can have various aplications, but here we'll focus on using it for testing references. And its worth it to mention that the children will only contain stored properties — you will not find functions and computed properties in there 😉!

Finding references

Using Mirror, we can now inspect private properties and assert their values and/or references in our scene.

Here, the constant interactor is a new reference the very own Interactor of the instancedviewController, and now we can access all of its properties, call its methods and even create a new Mirror reflecting it.

Since every child has a label, which is the name of its property on the code, and a value, that is a reference to the same value of the property, if finding the right value we can test if its reference is the one we expect it to be.

Please note that, in order to do so, we had to know the name of the property we wanted to find, and that we need to cast it to the expected type because value is an Any.

We could have made the same thing looking for the first child with the value of an expected type, not using the label:

But that would be a problem if the reflected object had more than one property of the same type!

Testing our references

Now that we know how to extract our properties, we can start testing if everything is connected as we expect.

For example, in our VIP architecture, the Presenter has a weak reference to the ViewController which is set by the Creator, and we want to make sure this reference is being set. If for some reason, someone deletes this line, there is no build or compiling warning, but our test will break and prevent this issue to go into production code.

In order to do that, we can reflect the Interactor and from it the Presenter and test the references.

Thats it! We've create a test that checks if our Creator is setting correclty the reference of our Presenter.

The operator === compares whether the two operands point to the same object. The guard guarantees that the presentersView is not opcional, and the assert guarantees that the Presenter references the same ViewController returned by the Creator — as our architecture dictates.

We made the reflections inside a guard let because the result of this operation is optional, and making a Mirror of an optional object is actually reflecting an enum with cases .some(Value) and .none. Iterate over these children is not the same as iterating over a non-optional object.

If you want to find and test a property that is not stored by reference, like classes, but by value, like enums or structs, it does not make sense to compare them using ===, because they will not reference the same position in memory, but you can check if they have the expected values.

Making everything a little bit prettier

Mirror gives us a lot of superpowers, but the syntax is kinda ugly when we need to make a series of reflections to reach the property we want to test.

And personally, I'm not a fan of the loose raw strings with the names of the properties I'm reflecting. So, a nice solution is to wrap all the reflection process and create constants for the property names:

This way, our Creatr's test gets much more readable:

And now, you can make pretty tests for all your references, test your complex architectures, and basically, make sure that everything you have instanced and injected are being referenced correctly preventing a bunch of bugs on your project.

Take a look into the Mirror — that's all folks!

When we started testing our Creators with reflection here on iFood Brazil, we have prevented a lot of bugs — sometimes you are changing something on the code and you remove the reference by accident, or you have a really complex architecture, and those tests will allow you to identify these issues and fix them right away!

Now that you have learned a little bit more about reflection on tests, you'll be able to prevent various bugs too :)

Nice testing! | ¡ƃuıʇsǝʇ ǝɔıu

If you want, this same article is also available in Portuguese!

--

--