Traits for testing in Kotlin
Using traits for testing is a fairly popular pattern in Kotlin. Think of integration tests in backend development: They need to simulate calling this application endpoints. We like to extract that into functions, like this one:
Since we might have many endpoints, we like to group them together. A popular way is to define them in interfaces. We will call them traits, and suffix their names with "Trait".
By definition, a trait is a concept representing a set of methods that can be used to extend the functionality of a class. Tere you can find a deeper explanation of this pattern.
Now each test class can define what traits it needs to use. For example,
ArticlesApiTests might need
CourseApiTests might need
The patterns work perfectly well, as long as those traits do not need to access any test objects. But what if they do? For instance, when we login with Google, a good practice is to verify the data with Google. This is what I defined here as
GoogleAccountVerifier. For tests, it needs to be mocked. Although, some data needs to be set there, if we want to register a user on our tests. Therefore, the method
requestRegisterUser should have access to the fake GoogleAccountVerifier used in the project. It is even more important, if we want to define methods like
adminExists that are used to setup situation for other integration tests.
A common practice is that such fake objects (like
randomStringProvider) are defined on some base integration test class (in this case, I called it
So, how can we let trait access these fakes? Time for a trick, that every Kotlin developer using this pattern should know. We need to define an interface with the property we need to access. We can name it
FakeGoogleAccountVerifierProvider, but it might as well hold more values and have more generic name. We will implement it both by
IntegrationTest and by
UserApiTrait can use the property, because interface makes sure it will be present in the final object.
IntegrationTest overrides it, so tests do not need to. This way traits can use objects defined by the base class.
This is the last puzzle needed when we use traits in Kotlin.
The traits pattern is popular in more dynamic languages, like Groovy. In Kotlin, I often see it used for testing, especially integration testing on backend applications. In Allegro, where I work, it is used widely and seems to work really well for us. I hope you know how to use it as well, and it might help you organize requests on your integration tests.