
Sealed Classes Unit Tests💥
Some months ago, I was working in an Android project where I decided to create a view template that based on the sealed class
received on the view, I was able to show different layout structures: one of those possible view structures would have a title, subtitle and image. Another one, those three elements plus an extra text field and so forth.
At some point, I felt the need of testing the type of sealed class
that the View Model was able to notify the observer (View) through LiveData. And I found an interesting post by Danny Preussler, where he explained a great approach using some factories, annotations and generics (Parameterized tests with Kotlin’s Sealed Classes).
In his project, he was able to test many different sealed classes
: simple, nested and custom. But I decided to focus on the custom one, which is the most common type that I usually work with: different data classes within the sealed class
, each one, with different parameters.
I used some common parameters in all of the sealed sub-classes
. To achieve that, I defined an interface that had got all of those parameters:
And the sealed class I defined, as example, implementing that interface is:
As you can see, it contains a class ErrorCode
, annotated with @InstagramErrorCode, which I will explain later:
Test goals 🎯
The first thing I wanted to test was, the expected sealed sub-class
, using Parameterized Test
. So I could pass as arguments the different cases with the expected KClass.
And the second thing, I wanted to achieve in my test was the different constructors availability check. That confirms the number of data classes defined within the sealed class
.
Parameterized Test by Type 🔬
Test by Class 📦
WHY another custom Factory ⁉️
In order to use the class developed by Danny Preussler SealedClassesArgumentsProvider
, we need to identify and return a type value from the KClassifier
represented by every parameter.
As I decided to add a List
and an Enum Class
, I must specify the returned value. And in the case of the Enum Class
, I thought that an interesting way to do it, was finding the annotation specified for that class, then returning a default Enum Type asErrorCode.TimeOut
WHY another annotation ⁉️
When I was specifying the return type from the KClassifier
I found there was a better solution than the first approach (hardcoded value) I made.
Let’s compare this initial solution (NOT GOOD):
else -> if ((type.classifier as KClass<out Any>).qualifiedName == “sctestingplayground.ErrorCode”) ErrorCode.TimeOut else null
And let’s check now, the improvement using the findAnnotation
inline function:
else -> if ((type.classifier as KClass<out Any>).findAnnotation<InstagramErrorCode>() != null) ErrorCode.TimeOut else null
Code
You can find the entire example in my Github Kotlin repository: