Abaks: Testing Use Cases
The Use Cases is a simple application-dependant wiring layer,
however, I tend to have one or two tests to ensure that Interpreters
are well coordinating (usually in the nominal case).
But unlike Core domain/Entities, it'll require a bit more work.
Let's review the test case:
describe "UseCases" $
around withFixture $ do
it "All chained commands should work" $ \fixture ->
runUsecase
fixture
( runError @Text $ do
periodId <- createPeriod periodName periodStart periodEnd (Amount 0) >>= fromEither
addEntry periodId anEntry >>= fromEither
changeAmountEntry periodId anEntry.entryId (Amount 1500) >>= fromEither
validateEntry periodId anEntry.entryId >>= fromEither
commentEntry periodId anEntry.entryId "The Hateful 8: too cool" >>= fromEither
markInClonflictEntry periodId anEntry.entryId "way too expensive" >>= fromEither
deleteEntry periodId anEntry.entryId "wrong period" >>= fromEither
)
`shouldReturn` Right ()
It's roughly a copy-paste of one of a nominal test case of the core domain.
We relied on fromEither
to shortcut de process (it will generate an Error Text
if a Left Text
occurs).
Note that it is also a way to describe how use cases are supposed to be chained.
One thing to notice is the runUsecase fixture
used to run Use Cases defined as:
newtype Fixture = Fixture
{ runUsecase :: forall a. Sem '[EventSourceEffect AbaksEvent, Final IO] a -> IO a
}
hspec
not being able to run Sem r a
directly.
We also need to inject (the Args
of the it
, \fixtures ->
), this is done through around withFixture
:
withFixture action = action $ Fixture $ runFinal . runMemoryUnsafe
Alternatively, we could also have directly a final function to do it, which would have been simpler.
It would have been, even though, in real world you may have additional context (a database, etc.) you want to inject, you may also want to change interpretation.