Testing
The Model-View-Update architecture used by Fabulous makes it simple to unit test every part of your application.
Apps are composed of 3 key pure F# functions: init
, update
and view
They take some parameters and return a value. Ideal for unit testing.
Testing init
init
init
is the easiest one to test.
It usually takes nothing and returns a value.
Let’s take this code for example:
Here we can make sure that the default state stays exact throughout the life of the project.
So using our favorite unit test framework (here we use FsUnit for this example), we can write a test that will check if the value returned by init
is the one we expect.
Testing update
update
update
can be more complex but it remains a pure F# function.
Testing it is equivalent to what we just did with init
.
Let’s take this code for example:
We can write the following tests:
Testing init
and update
when using commands
init
and update
when using commandsCommands are a great way for executing a set of tasks (asynchronous or not) after receiving a message.
But behind the scenes, Cmd<'msg>
is really only an array of functions. This makes testing Cmd<'msg>
really difficult (no way to know what the functions are) and the functions init
and update
as well.
In the case you want to unit test your code, even if you’re using Cmd<'msg>
inside init
and update
, the best way is to use of the CmdMsg
pattern.
This is a general pattern, applicable when using an Elm-like programming model. It is not linked to Fabulous specifically.
Fabulous only provides some helpers to help you achieve this with less code.
The principle is to replace any direct usage of Cmd<'msg>
from init
and update
, and instead use a discriminated union called CmdMsg
.
Doing this transforms the output of both init
and update
to pure data output, which can then be easily unit tested
The actual commands are still executed as Cmd<'msg>
though.
So in order to make this work with Fabulous, you need a function that will convert a CmdMsg
to a Cmd<'msg>
Fabulous then helps you boot your application using Program.statefulWithCmdMsg
Note that Program.statefulWithCmdMsg
doesn’t do anything magic.
It only applies mapCommands
to any CmdMsg
returned by init
and update
.
You could achieve the exact same behavior by converting them yourself and using Program.stateful
.
Last updated