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.