Since the elves started using Red (https://raku-advent.blog/2019/12/21/searching-for-a-red-gift/) they thought it was missing a better way of testing code that uses it. They tested it using several SQL files that would be used before each test to populate the database with test data. That works ok, but that’s too hard to understand what’s expected from the test not looking at those SQL files. It also added a big chunk of boilerplate at the beginning of each test file for runnig the SQL. In every file it’s the same code, changing only what file to use. So they decided to look for some better way of doing that.
Searching for it they found a new module called RedFactory. It’s specific for Red and uses factories to make it easier to write and read tests written for code that uses Red. The idea about factories is to have a easy way of adding data to your test DB with default values making that easy to populate the test DB at the same file as the test and setting speccific values only for what is needed on the test.
The first thing to be done to use factories is to create the factories themselves. so, for testing the code created here first we would need to create a factory like this one:
That creates 2 factories, one for
Child model and another one for
Gift model called
gift respectively. A factory doesn’t need to have the same name as its model, but the first factory for a model usualy does. Other factories for that model usualy get more specific names and has more specialised data;
child factory sets default values for 2 columns (
gift sets only one (
name). So lets see how to use that.
RedFactory‘s factories will use any Red‘s DB connection you set, so, if you do:
That will create a new
Child entry on your Pg database. That row will contain:
$child will have the object created by Red.
But you usualy don’t want to mess with your DB while testing. For helping with that,
RedFactory has a helper for running that on a thrown-away DB. So, you could do that instead:
That will work exactly as the other snippet, but using a SQLite database in memory. Another way of doing that is using
factory-run that will receive a block that will use the in memoty SQLite DB and will receive the RedFactory object, where you can call its methods instead of using the factories functions, for example:
And it will do exactly the same as the previous snippet.
Ok, that’s cool. But what about testing? Let’s do that! The elves’ code has a function to return the the number of children from a specific country (
&children-on-country), so they started writing the test like this:
This is using
child factory passing a
country value to be used different from default. it also uses
UInt as first param, that indicates
.create to create as many rows as the number passed, and returns a list of those created objects.
But there is a “problem” with that. All created children will have the same name. We can do a small change on that factory to prevent that.
You can pass a block to to have it generate dynamic data for the column. That block will receive a Factory objects that over other things has a method that will return an incremented UInt every time it’s called (by model) (
country is also changed, now it will return a random country for each raw created.
So, that made the elves’ tests much simpler to grok.
For more information about RedFactory, please look at https://github.com/FCO/RedFactory.