Test builders (experimental)
⚠️ Test builders are
Apollo Kotlin provides test builders that enable you to instantiate your GraphQL model classes with default values. Test builders are especially helpful for testing models with a large number of fields or a deeply nested hierarchy. They automatically populate the __typename
field and deduplicate merged fields whenever possible.
Enabling test builders
Test builders are not enabled by default, because they aren't useful for every application and they generate additional code. To enable them, set the generateTestBuilders
option to true
:
apollo {service("service") {// ...// Enable test builder generationgenerateTestBuilders.set(true)}}
This generates a builder DSL for each model used by your operations. These DSLs are based on each model's fields. Using the DSLs, you can set the values of fields you require for a particular test, and mocked values are set automatically for other fields.
Example usage
Let's say we're building a test that uses a mocked result of the following query:
query HeroForEpisode($ep: Episode!) {hero(episode: $ep) {firstNamelastNameageship {modelspeed}friends {firstNamelastName}... on Droid {primaryFunction}... on Human {height}}}
Here's how we can use the corresponding test builder for that mocked result:
// Import the query's test builderimport com.example.test.HeroForEpisodeQuery_TestBuilder.Data@Testfun test() {val data = HeroForEpisodeQuery.Data {// Set values for particular fields of the queryhero = humanHero {firstName = "John"age = 42friends = listOf(humanFriend {firstName = "Jane"},humanFriend {lastName = "Doe"})ship = ship {model = "X-Wing"}}}assertEquals("John", data.hero.firstName)assertEquals(42, data.hero.age)}
In this example, the hero
field is a Human
object with specified values for firstName
and age
. The values for lastName
and height
are automatically populated with mock values.
Similarly, values for the ship's speed, the 1st friend's last name and 2nd friend's first name are automatically populated.
You can replace humanHero
above with droidHero
to create a Droid
object instead, or specify otherHero
to create an object that is neither a Human
nor a Droid
.
Configuring default field values
To assign default values to fields, test builders use an implementation of the TestResolver
interface. By default, they use an instance of DefaultTestResolver
.
The DefaultTestResolver
gives each String
field the field's name as its default value, and it increments a counter as it assigns default values for Int
fields. It defines similar default behavior for other types.
You can create your own TestResolver
implementation (optionally extending DefaultTestResolver
for a head start). You then pass this implementation as a parameter to the Data
function, like so:
// A TestResolver implementation that assigns -1 to all Int fieldsval myTestResolver = object : DefaultTestResolver() {override fun resolveInt(path: List<Any>): Int {return -1}}@Testfun test() {val data = HeroForEpisodeQuery.Data(testResolver = myTestResolver) {hero = humanHero {firstName = "John"}}// Unspecified Int field is -1assertEquals(-1, data.hero.age)}