Skip to content

Instantly share code, notes, and snippets.

@StevenXL
Last active November 11, 2019 18:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save StevenXL/49c10bd1bceb57b5ae26e1e726688bd6 to your computer and use it in GitHub Desktop.
Save StevenXL/49c10bd1bceb57b5ae26e1e726688bd6 to your computer and use it in GitHub Desktop.
Example integration of `hspec` and `persistent-sqlite`
#!/usr/bin/env stack
-- stack --resolver lts-11.6 script
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeApplications #-}
import Control.Monad.IO.Class (MonadIO)
import Control.Monad.Reader (ReaderT)
import Database.Persist.Sqlite (SqlBackend, LogFunc, Filter, Entity, runSqlite, runMigration, wrapConnection, rawSql, insert, count, runSqlConn, transactionSave, transactionUndo)
import Database.Persist.TH
import Database.Sqlite (open)
import Test.Hspec
import Conduit (MonadUnliftIO)
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Person
name String
age Int Maybe
deriving Show
BlogPost
title String
authorId PersonId
deriving Show
|]
main :: IO ()
main = hspec $ spec
spec :: Spec
spec = withDatabaseConnection specs
specs :: SpecWith SqlBackend
specs = describe "insertion" $ do
it "can insert a person" $ \c -> do
personCount <- runDb c $ do
transactionSave
let person = Person "John Doe" (Just 35)
_ <- insert person
count <- getPersonCount
transactionUndo
pure count
personCount `shouldBe` 1
it "tests don't interact" $ \c -> do
personCount <- runDb c $ do
transactionSave
let person = Person "John Doe" (Just 35)
let person' = Person "Jane Doe" (Just 35)
insert person
insert person'
count <- getPersonCount
transactionUndo
pure count
personCount `shouldBe` 2 -- will be 3 if first tests interacts
getPersonCount :: MonadIO m => ReaderT SqlBackend m Int
getPersonCount = count ([] :: [Filter Person])
withDatabaseConnection :: SpecWith SqlBackend -> Spec
withDatabaseConnection = beforeAll dbSetup
runDb :: (MonadUnliftIO m) => SqlBackend -> ReaderT SqlBackend m a -> m a
runDb = flip runSqlConn
-- | Use an in-memory SQLite database, run the migration, return the connection
-- for use the the specs
dbSetup :: IO SqlBackend
dbSetup = do
rawConn <- open ":memory:"
conn <- wrapConnection rawConn noLogging
_ <- runSqlConn (runMigration migrateAll) conn
return conn
-- | We don't care about logging
noLogging :: LogFunc
noLogging _ _ _ _ = return ()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment