#readwise
# Test Data Generator Monad

## Metadata
- Author: [[Mark Seemann]]
- Full Title: Test Data Generator Monad
- URL: https://blog.ploeh.dk/2023/02/27/test-data-generator-monad/
## Highlights
You can now combine `choose` with `DateTime.DaysInMonth` to generate a valid day:
```csharp
public static Generator<int> Day(int year, int month)
{
var daysInMonth = DateTime.DaysInMonth(year, month);
return Gen.Choose(1, daysInMonth);
}
```
Let's pause and consider the implications. The point of this example is to demonstrate why it's practically useful that Test Data Generators are monads. Keep in mind that monads are functors you can flatten. When do you need to flatten a functor? Specifically, when do you need to flatten a Test Data Generator? Right now, as it turns out.
The `Day` method returns a `Generator<int>`, but where do the `year` and `month` arguments come from? They'll typically be produced by another Test Data Generator such as `choose`. Thus, if you only *map* (`Select`) over previous Test Data Generators, you'll produce a `Generator<Generator<int>>`:
```csharp
Generator<int> genYear = Gen.Choose(1970, 2050);
Generator<int> genMonth = Gen.Choose(1, 12);
Generator<(int, int)> genYearAndMonth = genYear.Apply(genMonth);
Generator<Generator<int>> genDay =
genYearAndMonth.Select(t => Gen.Choose(1, DateTime.DaysInMonth(t.Item1, t.Item2)));
```
This example uses an `Apply` overload to combine `genYear` and `genMonth`. As long as the two generators are independent of each other, you can use the [applicative functor](https://blog.ploeh.dk/2018/10/01/applicative-functors) capability to combine them. When, however, you need to produce a new generator from a value produced by a previous generator, the functor or applicative functor capabilities are insufficient. If you try to use `Select`, as in the above example, you'll produce a nested generator.
Since it's a monad, however, you can `Flatten` it: ([View Highlight](https://read.readwise.io/read/01gysazegs3aje8z84n6vmx68q))
---
Test Data Generators form monads. This is useful when you need to generate test data that depend on other generated test data ([View Highlight](https://read.readwise.io/read/01gysb20n2x6hbf40tjh7npz9v))
---