0

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?

Johan
  • 37,479
  • 32
  • 149
  • 237

3 Answers3

2

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.

Johan
  • 37,479
  • 32
  • 149
  • 237
MaxGabriel
  • 7,617
  • 4
  • 35
  • 82
  • This is a good idea but databases like MongoDB generates an id by default and it's not something that you necessarily supply to the db. So is not exactly what I'm asking for. – Johan Dec 06 '17 at 20:03
  • @Johan I'm suggesting you create the entity using e.g. MongoDB, then use any database-populated fields it returns to you to create a record which you then do comparisons with. – MaxGabriel Dec 06 '17 at 21:45
  • Oh sorry, I misunderstood. – Johan Dec 07 '17 at 05:51
2

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"
Chris Martin
  • 30,334
  • 10
  • 78
  • 137
2

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 #-}
Johan
  • 37,479
  • 32
  • 149
  • 237