Unleashing the Power of Reusable Test Data Factories
Crafting effective tests is as vital as writing clean production code. A well-structured test not only validates functionality but also serves as documentation for the system. However, creating such tests often encounters a common roadblock – the excess baggage of fluff. This includes generating test data, defining parameters for the “system under test,” creating responses for mocks/stubs, and establishing expectations for asserts.
Enter reusable test data factories, introduced by Martin Fowler as the “Object Mother.” This approach streamlines the manual instantiation and population of complex text fixtures, avoiding boilerplate code.
To enhance this methodology, we turn to Instancio, a library that not only streamlines test data creation but also allows for a high degree of customization. With Instancio, we can fill our Object Mother with reasonable defaults, ensuring a seamless and efficient testing process.
Let’s explore a practical example within the context of a cooking app. Consider two services – MealService and ShoppingService. Our test focuses on MealService; we validate that ShoppingService is invoked with a shopping list of essential ingredients.
---
title: Cooking Domain
---
classDiagram
class MealService {
cook(meal:Meal)
}
class ShoppingService {
buy(list: ShoppingList)
}
class ShoppingList {
items: String[]
}
class MealType {
<<enum>>
BREAKFAST
LUNCH
DINNER
SNACK
DESSERT
}
class IngredientType {
<<enum>>
VEGETABLE
FRUIT
PROTEIN
GRAIN
DAIRY
SPICE
SAUCE
}
class Ingredient {
name: String
amount: double
unit: String
type: IngredientType
}
class Step {
instruction: String
duration: Duration
}
class Recipe {
steps: List<Step>
getDuration(): Duration
}
class Meal {
name: String
mealType: MealType
ingredients: List<Ingredient>
recipe: Recipe
}
MealService -- Meal
ShoppingService -- ShoppingList
Meal -- MealType
Meal o-- Ingredient
Meal o-- Recipe
Ingredient -- IngredientType
Recipe *-- Step
In this example, we’ve set up a single ‘object mother’ test data factory class for the entire domain.
Its main job is to create and provide named test data builders. Once you have a builder,
you can simply invoke the ‘build()’ method and obtain a fully populated complex domain object.
Additionally, we offer several convenient customization methods, enabling users to adjust specific values within the created domain object.
Internally, these builders leverage the capabilities of Instancio.