Match "any string" in Haskell record in HSpec test

243 Views Asked by At

I have a data class Entity which is defined like this:

data Entity = Entity { id :: String, name :: String }

and a function that returns IO Entity:

newPersistentEntity :: String -> IO Entity

And I'd like to write an HSpec test for this:

spec :: Spec
spec = describe "newPersistentEntity function" $
       it "returns a new Entity with a generated id and the specified name" $
       newPersistentEntity "myName" `shouldReturn` Entity {id = <any string>, name = "myName"}

The problem is that the id is a UUID generated by the database. I want to assert that the id is a string to make the test pass.

How can I achieve this?

3

There are 3 best solutions below

3
On BEST ANSWER

Can you create the record, then use its id value to create the record you're comparing against? Something like:

new <- newPersistentEntity "myName"
new `shouldBe` Entity { id = (id new), name = "myName" }

(Note: don't have enough information to test this code, treat this as somewhat pseudo code).

As a side note, your code doesn't look like normal Persistent code, so I'm assuming you're using a different library.

0
On

The id of an Entity can't not be a String, because static typing. But you probably do want to force its evaluation to ensure that it isn't bottom.

spec :: Spec
spec = describe "newPersistentEntity function" $
    it "returns a new Entity with a generated id and the specified name" $ do
        x <- newPersistentEntity "myName"
        pure $! id x  -- Force evaluation of the `id` field to ensure that
                      -- the database actually did return a string here
        name x `shouldBe` "myName"
0
On

I actually solved this myself in a different way that I'll show here for context. You probably shouldn't use it since the accepted answer is easier to understand and less verbose.

spec :: Spec
spec = describe "newPersistentEntity function" $
       it "returns a new Entity with a generated id and the specified name" $
       newPersistentEntity "myName" >>= (`shouldSatisfy` (\case
           Entity {id = _, name = "myName"} -> True
           _ -> False))

But for this to work you also need to apply the lamda case language extension:

{-# LANGUAGE LambdaCase #-}