How to use QuickCheck to test the database-related functions?

I need to check out a variety of functions that access the database (via Persistent). Although I can do this using monadicIO and withSqlitePool , it will lead to inefficient tests. Each test, rather than the property, but the test, create and destroy database pool. How to prevent this?

Important: Forget about the effectiveness, or elegance. I was not even able to create the types of QuickCheck and Persistent to create.

 instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck (PropertyM a) instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck (PropertyM a) instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck > arbitrary instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck > arbitrary instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck > arbitrary instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck ] instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck $ createDownload_ Nothing instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck DownloadStatus =. instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck $ createDownload_ (Just pid) instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck ^. status) of instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck > return True instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck return True instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck -> return True), instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck -> return False) instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck :" $ do instance (Monad a) => MonadThrow (PropertyM a) instance (MonadThrow a) => MonadCatch (PropertyM a) type NwApp = SqlPersistT IO prop_childCreation :: PropertyM NwApp Bool prop_childCreation = do uid <- pick $ UserKey <$> arbitrary lid <- pick $ LogKey <$> arbitrary gid <- pick $ Aria2Gid <$> arbitrary let createDownload_ = createDownload gid lid uid [] (Entity pid _) <- run $ createDownload_ Nothing dstatus <- pick arbitrary parent <- run $ updateGet pid [DownloadStatus =. dstatus] let test = do (Entity cid child) <- run $ createDownload_ (Just pid) case (parent ^. status, child ^. status) of (DownloadComplete ChildrenComplete, DownloadComplete ChildrenNone) -> return True (DownloadComplete ChildrenIncomplete, DownloadIncomplete) -> return True _ -> return False test `catches` [ Handler (\ (e :: SanityException) -> return True), Handler (\ (e :: SomeException) -> return False) ] -- How do I write this function? runTests = monadicIO $ runSqlite ":memory:" $ do -- whatever I do, this function fails to typecheck 
+5
source share
3 answers

To avoid the creation and destruction of a pool of database and configure the database only once, you need to use withSqliteConn in its main features from the outside, and then convert each property for the use of this compound as in this code:

 share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Person name String age Int Maybe deriving Show Eq |] type SqlT m = SqlPersistT (NoLoggingT (ResourceT m)) prop_insert_person :: PropertyM (SqlT IO) () prop_insert_person = do personName <- pick arbitrary personAge <- pick arbitrary let person = Person personName personAge -- This assertion will fail right now on the second iteration -- since I have not implemented the cleanup code numEntries <- run $ count ([] :: [Filter Person]) assert (numEntries == 0) personId <- run $ insert person result <- run $ get personId assert (result == Just person) main :: IO () main = runNoLoggingT $ withSqliteConn ":memory:" $ \connection -> lift $ do let -- Run a SqlT action using our connection runSql :: SqlT IO a -> IO a runSql = flip runSqlPersistM connection runSqlProperty :: SqlT IO Property -> Property runSqlProperty action = ioProperty . runSql $ do prop <- action liftIO $ putStrLn "\nDB reset code (per test) goes here\n" return prop quickCheckSql :: PropertyM (SqlT IO) () -> IO () quickCheckSql = quickCheck . monadic runSqlProperty -- Initial DB setup code runSql $ runMigration migrateAll -- Test as many quickcheck properties as you like quickCheckSql prop_insert_person "] [persistLowerCase | share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Person name String age Int Maybe deriving Show Eq |] type SqlT m = SqlPersistT (NoLoggingT (ResourceT m)) prop_insert_person :: PropertyM (SqlT IO) () prop_insert_person = do personName <- pick arbitrary personAge <- pick arbitrary let person = Person personName personAge -- This assertion will fail right now on the second iteration -- since I have not implemented the cleanup code numEntries <- run $ count ([] :: [Filter Person]) assert (numEntries == 0) personId <- run $ insert person result <- run $ get personId assert (result == Just person) main :: IO () main = runNoLoggingT $ withSqliteConn ":memory:" $ \connection -> lift $ do let -- Run a SqlT action using our connection runSql :: SqlT IO a -> IO a runSql = flip runSqlPersistM connection runSqlProperty :: SqlT IO Property -> Property runSqlProperty action = ioProperty . runSql $ do prop <- action liftIO $ putStrLn "\nDB reset code (per test) goes here\n" return prop quickCheckSql :: PropertyM (SqlT IO) () -> IO () quickCheckSql = quickCheck . monadic runSqlProperty -- Initial DB setup code runSql $ runMigration migrateAll -- Test as many quickcheck properties as you like quickCheckSql prop_insert_person ResourceT m)) share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Person name String age Int Maybe deriving Show Eq |] type SqlT m = SqlPersistT (NoLoggingT (ResourceT m)) prop_insert_person :: PropertyM (SqlT IO) () prop_insert_person = do personName <- pick arbitrary personAge <- pick arbitrary let person = Person personName personAge -- This assertion will fail right now on the second iteration -- since I have not implemented the cleanup code numEntries <- run $ count ([] :: [Filter Person]) assert (numEntries == 0) personId <- run $ insert person result <- run $ get personId assert (result == Just person) main :: IO () main = runNoLoggingT $ withSqliteConn ":memory:" $ \connection -> lift $ do let -- Run a SqlT action using our connection runSql :: SqlT IO a -> IO a runSql = flip runSqlPersistM connection runSqlProperty :: SqlT IO Property -> Property runSqlProperty action = ioProperty . runSql $ do prop <- action liftIO $ putStrLn "\nDB reset code (per test) goes here\n" return prop quickCheckSql :: PropertyM (SqlT IO) () -> IO () quickCheckSql = quickCheck . monadic runSqlProperty -- Initial DB setup code runSql $ runMigration migrateAll -- Test as many quickcheck properties as you like quickCheckSql prop_insert_person ) share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Person name String age Int Maybe deriving Show Eq |] type SqlT m = SqlPersistT (NoLoggingT (ResourceT m)) prop_insert_person :: PropertyM (SqlT IO) () prop_insert_person = do personName <- pick arbitrary personAge <- pick arbitrary let person = Person personName personAge -- This assertion will fail right now on the second iteration -- since I have not implemented the cleanup code numEntries <- run $ count ([] :: [Filter Person]) assert (numEntries == 0) personId <- run $ insert person result <- run $ get personId assert (result == Just person) main :: IO () main = runNoLoggingT $ withSqliteConn ":memory:" $ \connection -> lift $ do let -- Run a SqlT action using our connection runSql :: SqlT IO a -> IO a runSql = flip runSqlPersistM connection runSqlProperty :: SqlT IO Property -> Property runSqlProperty action = ioProperty . runSql $ do prop <- action liftIO $ putStrLn "\nDB reset code (per test) goes here\n" return prop quickCheckSql :: PropertyM (SqlT IO) () -> IO () quickCheckSql = quickCheck . monadic runSqlProperty -- Initial DB setup code runSql $ runMigration migrateAll -- Test as many quickcheck properties as you like quickCheckSql prop_insert_person the second iteration share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Person name String age Int Maybe deriving Show Eq |] type SqlT m = SqlPersistT (NoLoggingT (ResourceT m)) prop_insert_person :: PropertyM (SqlT IO) () prop_insert_person = do personName <- pick arbitrary personAge <- pick arbitrary let person = Person personName personAge -- This assertion will fail right now on the second iteration -- since I have not implemented the cleanup code numEntries <- run $ count ([] :: [Filter Person]) assert (numEntries == 0) personId <- run $ insert person result <- run $ get personId assert (result == Just person) main :: IO () main = runNoLoggingT $ withSqliteConn ":memory:" $ \connection -> lift $ do let -- Run a SqlT action using our connection runSql :: SqlT IO a -> IO a runSql = flip runSqlPersistM connection runSqlProperty :: SqlT IO Property -> Property runSqlProperty action = ioProperty . runSql $ do prop <- action liftIO $ putStrLn "\nDB reset code (per test) goes here\n" return prop quickCheckSql :: PropertyM (SqlT IO) () -> IO () quickCheckSql = quickCheck . monadic runSqlProperty -- Initial DB setup code runSql $ runMigration migrateAll -- Test as many quickcheck properties as you like quickCheckSql prop_insert_person code share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Person name String age Int Maybe deriving Show Eq |] type SqlT m = SqlPersistT (NoLoggingT (ResourceT m)) prop_insert_person :: PropertyM (SqlT IO) () prop_insert_person = do personName <- pick arbitrary personAge <- pick arbitrary let person = Person personName personAge -- This assertion will fail right now on the second iteration -- since I have not implemented the cleanup code numEntries <- run $ count ([] :: [Filter Person]) assert (numEntries == 0) personId <- run $ insert person result <- run $ get personId assert (result == Just person) main :: IO () main = runNoLoggingT $ withSqliteConn ":memory:" $ \connection -> lift $ do let -- Run a SqlT action using our connection runSql :: SqlT IO a -> IO a runSql = flip runSqlPersistM connection runSqlProperty :: SqlT IO Property -> Property runSqlProperty action = ioProperty . runSql $ do prop <- action liftIO $ putStrLn "\nDB reset code (per test) goes here\n" return prop quickCheckSql :: PropertyM (SqlT IO) () -> IO () quickCheckSql = quickCheck . monadic runSqlProperty -- Initial DB setup code runSql $ runMigration migrateAll -- Test as many quickcheck properties as you like quickCheckSql prop_insert_person ] :: [Filter Person]) share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Person name String age Int Maybe deriving Show Eq |] type SqlT m = SqlPersistT (NoLoggingT (ResourceT m)) prop_insert_person :: PropertyM (SqlT IO) () prop_insert_person = do personName <- pick arbitrary personAge <- pick arbitrary let person = Person personName personAge -- This assertion will fail right now on the second iteration -- since I have not implemented the cleanup code numEntries <- run $ count ([] :: [Filter Person]) assert (numEntries == 0) personId <- run $ insert person result <- run $ get personId assert (result == Just person) main :: IO () main = runNoLoggingT $ withSqliteConn ":memory:" $ \connection -> lift $ do let -- Run a SqlT action using our connection runSql :: SqlT IO a -> IO a runSql = flip runSqlPersistM connection runSqlProperty :: SqlT IO Property -> Property runSqlProperty action = ioProperty . runSql $ do prop <- action liftIO $ putStrLn "\nDB reset code (per test) goes here\n" return prop quickCheckSql :: PropertyM (SqlT IO) () -> IO () quickCheckSql = quickCheck . monadic runSqlProperty -- Initial DB setup code runSql $ runMigration migrateAll -- Test as many quickcheck properties as you like quickCheckSql prop_insert_person :" $ \ connection -> lift $ do share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Person name String age Int Maybe deriving Show Eq |] type SqlT m = SqlPersistT (NoLoggingT (ResourceT m)) prop_insert_person :: PropertyM (SqlT IO) () prop_insert_person = do personName <- pick arbitrary personAge <- pick arbitrary let person = Person personName personAge -- This assertion will fail right now on the second iteration -- since I have not implemented the cleanup code numEntries <- run $ count ([] :: [Filter Person]) assert (numEntries == 0) personId <- run $ insert person result <- run $ get personId assert (result == Just person) main :: IO () main = runNoLoggingT $ withSqliteConn ":memory:" $ \connection -> lift $ do let -- Run a SqlT action using our connection runSql :: SqlT IO a -> IO a runSql = flip runSqlPersistM connection runSqlProperty :: SqlT IO Property -> Property runSqlProperty action = ioProperty . runSql $ do prop <- action liftIO $ putStrLn "\nDB reset code (per test) goes here\n" return prop quickCheckSql :: PropertyM (SqlT IO) () -> IO () quickCheckSql = quickCheck . monadic runSqlProperty -- Initial DB setup code runSql $ runMigration migrateAll -- Test as many quickcheck properties as you like quickCheckSql prop_insert_person a share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Person name String age Int Maybe deriving Show Eq |] type SqlT m = SqlPersistT (NoLoggingT (ResourceT m)) prop_insert_person :: PropertyM (SqlT IO) () prop_insert_person = do personName <- pick arbitrary personAge <- pick arbitrary let person = Person personName personAge -- This assertion will fail right now on the second iteration -- since I have not implemented the cleanup code numEntries <- run $ count ([] :: [Filter Person]) assert (numEntries == 0) personId <- run $ insert person result <- run $ get personId assert (result == Just person) main :: IO () main = runNoLoggingT $ withSqliteConn ":memory:" $ \connection -> lift $ do let -- Run a SqlT action using our connection runSql :: SqlT IO a -> IO a runSql = flip runSqlPersistM connection runSqlProperty :: SqlT IO Property -> Property runSqlProperty action = ioProperty . runSql $ do prop <- action liftIO $ putStrLn "\nDB reset code (per test) goes here\n" return prop quickCheckSql :: PropertyM (SqlT IO) () -> IO () quickCheckSql = quickCheck . monadic runSqlProperty -- Initial DB setup code runSql $ runMigration migrateAll -- Test as many quickcheck properties as you like quickCheckSql prop_insert_person (per test) goes here \ n" share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Person name String age Int Maybe deriving Show Eq |] type SqlT m = SqlPersistT (NoLoggingT (ResourceT m)) prop_insert_person :: PropertyM (SqlT IO) () prop_insert_person = do personName <- pick arbitrary personAge <- pick arbitrary let person = Person personName personAge -- This assertion will fail right now on the second iteration -- since I have not implemented the cleanup code numEntries <- run $ count ([] :: [Filter Person]) assert (numEntries == 0) personId <- run $ insert person result <- run $ get personId assert (result == Just person) main :: IO () main = runNoLoggingT $ withSqliteConn ":memory:" $ \connection -> lift $ do let -- Run a SqlT action using our connection runSql :: SqlT IO a -> IO a runSql = flip runSqlPersistM connection runSqlProperty :: SqlT IO Property -> Property runSqlProperty action = ioProperty . runSql $ do prop <- action liftIO $ putStrLn "\nDB reset code (per test) goes here\n" return prop quickCheckSql :: PropertyM (SqlT IO) () -> IO () quickCheckSql = quickCheck . monadic runSqlProperty -- Initial DB setup code runSql $ runMigration migrateAll -- Test as many quickcheck properties as you like quickCheckSql prop_insert_person ) -> IO () share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Person name String age Int Maybe deriving Show Eq |] type SqlT m = SqlPersistT (NoLoggingT (ResourceT m)) prop_insert_person :: PropertyM (SqlT IO) () prop_insert_person = do personName <- pick arbitrary personAge <- pick arbitrary let person = Person personName personAge -- This assertion will fail right now on the second iteration -- since I have not implemented the cleanup code numEntries <- run $ count ([] :: [Filter Person]) assert (numEntries == 0) personId <- run $ insert person result <- run $ get personId assert (result == Just person) main :: IO () main = runNoLoggingT $ withSqliteConn ":memory:" $ \connection -> lift $ do let -- Run a SqlT action using our connection runSql :: SqlT IO a -> IO a runSql = flip runSqlPersistM connection runSqlProperty :: SqlT IO Property -> Property runSqlProperty action = ioProperty . runSql $ do prop <- action liftIO $ putStrLn "\nDB reset code (per test) goes here\n" return prop quickCheckSql :: PropertyM (SqlT IO) () -> IO () quickCheckSql = quickCheck . monadic runSqlProperty -- Initial DB setup code runSql $ runMigration migrateAll -- Test as many quickcheck properties as you like quickCheckSql prop_insert_person like share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| Person name String age Int Maybe deriving Show Eq |] type SqlT m = SqlPersistT (NoLoggingT (ResourceT m)) prop_insert_person :: PropertyM (SqlT IO) () prop_insert_person = do personName <- pick arbitrary personAge <- pick arbitrary let person = Person personName personAge -- This assertion will fail right now on the second iteration -- since I have not implemented the cleanup code numEntries <- run $ count ([] :: [Filter Person]) assert (numEntries == 0) personId <- run $ insert person result <- run $ get personId assert (result == Just person) main :: IO () main = runNoLoggingT $ withSqliteConn ":memory:" $ \connection -> lift $ do let -- Run a SqlT action using our connection runSql :: SqlT IO a -> IO a runSql = flip runSqlPersistM connection runSqlProperty :: SqlT IO Property -> Property runSqlProperty action = ioProperty . runSql $ do prop <- action liftIO $ putStrLn "\nDB reset code (per test) goes here\n" return prop quickCheckSql :: PropertyM (SqlT IO) () -> IO () quickCheckSql = quickCheck . monadic runSqlProperty -- Initial DB setup code runSql $ runMigration migrateAll -- Test as many quickcheck properties as you like quickCheckSql prop_insert_person 

The full code, including import and extensions can be found in this sense .

Please note that I did not realize the functionality to clean the database between the tests, because I do not know how to do it as a whole with a constant, you have to implement it yourself (replace the cleaning action of filler, which simply prints a message right now).


You also do not need copies for MonadCatch / MonadThrow for PropertyM . Instead, you have to catch the Monad NwApp . So instead of this:

 let test = do run a ... run b test `catch` \exc -> ... 

instead, you must use the following code:

 let test = do a b return ...whether or not the test was successfull... let testCaught = test `catch` \exc -> ..handler code... ok <- test assert ok successfull ... let test = do a b return ...whether or not the test was successfull... let testCaught = test `catch` \exc -> ..handler code... ok <- test assert ok -> ..handler code ... let test = do a b return ...whether or not the test was successfull... let testCaught = test `catch` \exc -> ..handler code... ok <- test assert ok 
+3
source
 monadicIO :: PropertyM IO a -> Property runSqlite ":memory:" :: SqlPersistT (NoLoggingT (ResourceT m)) a -> ma prop_childCreation :: PropertyM NwApp Bool (NoLoggingT (ResourceT m)) a -> ma monadicIO :: PropertyM IO a -> Property runSqlite ":memory:" :: SqlPersistT (NoLoggingT (ResourceT m)) a -> ma prop_childCreation :: PropertyM NwApp Bool 

They do not make up. One of them belongs.

 monadic :: Monad m => (m Property -> Property) -> PropertyM ma -> Property 

It looks better than monadicIO . We can combine it and our requirement to use prop_childCreation the requirement to produce (m Property → Property).

 runSqlite ":memory:" :: SqlPersistT (NoLoggingT (ResourceT m)) a -> ma \f -> monadic f prop_childCreation :: (NwApp Property -> Property) -> Property (NoLoggingT (ResourceT m)) a -> ma runSqlite ":memory:" :: SqlPersistT (NoLoggingT (ResourceT m)) a -> ma \f -> monadic f prop_childCreation :: (NwApp Property -> Property) -> Property 

Rewrite NwApp, to facilitate the search:

 runSqlite ":memory:" :: SqlPersistT (NoLoggingT (ResourceT m)) a -> ma \f -> monadic f prop_childCreation :: (SqlPersistT IO Property -> Property) -> Property (NoLoggingT (ResourceT m)) a -> ma runSqlite ":memory:" :: SqlPersistT (NoLoggingT (ResourceT m)) a -> ma \f -> monadic f prop_childCreation :: (SqlPersistT IO Property -> Property) -> Property 

I just believe that all of a T at the end - it MonadTrans that means lift :: Monad m => ma -> T ma . Then we see that this is our chance to get rid of SqlPersistT:

 \fg -> monadic (f . runSqlite ":memory:" . g) prop_childCreation :: (IO Property -> Property) -> (SqlPersistT IO Property -> SqlPersistT (NoLoggingT (ResourceT m)) Property) -> Property 

We need once again to get rid of IO, so monadicIO can help us:

 \fg -> monadic (monadicIO . f . runSqlite ":memory:" . g) prop_childCreation :: (IO Property -> PropertyT IO a) -> (SqlPersistT IO Property -> SqlPersistT (NoLoggingT (ResourceT m)) Property) -> Property 

Time to raise to shine! Except that f we obviously throw Property in IO Property , and on the right, we need to somehow "fmap" in the part of the argument monads SqlPersistT. Well, we can ignore the first problem and put the other before the next step:

 \f -> monadic (monadicIO . lift . runSqlite ":memory:" . f (lift . lift)) prop_childCreation :: ((ma -> na) -> SqlPersistT ma -> SqlPersist na) -> Property 

Turns out, it looks just like Control.Monad.Morph MFunctor . I just pretend that SqlPersistT was an instance of this:

 monadic (monadicIO . lift . runSqlite ":memory:" . mmorph (lift . lift)) prop_childCreation :: Property 

Tada! Good luck in your search, maybe this will help a little.

Project exference trying to automate the process, which I have just passed. I heard that if I put such arguments as f and g, then ghc will tell you what type should go there.

0
source

(.lhs available at: http://lpaste.net/173182 )

Used packages:

 build-depends: base >= 4.7 && < 5, QuickCheck, persistent, persistent-sqlite, monad-logger, transformers 

Firstly, some imported:

  {-# LANGUAGE OverloadedStrings #-} module Lib2 where import Database.Persist.Sql import Database.Persist.Sqlite import Test.QuickCheck import Test.QuickCheck.Monadic import Control.Monad.Logger import Control.Monad.Trans.Class 

Here's a query that we want to check:

  aQuery :: SqlPersistM Int aQuery = undefined 

Of course, aQuery can take arguments. The important thing is that he returns the action SqlPersistM .

Here's how you can start the action SqlPersistM :

  runQuery = runSqlite ":memory:" $ do aQuery 

Even if PropertyM a monad transformer, it seems that the only useful way to use it - with PropertyM IO .

To get the effect of the IO-action SqlPersistM, we need a backend.

With that in mind, here is a sample database test:

  prop_test :: SqlBackend -> PropertyM IO Bool prop_test backend = do a <- run $ runSqlPersistM aQuery backend b <- run $ runSqlPersistM aQuery backend return (a == b) 

Here run coincides with the lift .

In order to perform a specific SqlPersistM backend, we need to perform a recovery:

  runQuery2 = withSqliteConn ":memory:" $ \backend -> do liftNoLogging (runSqlPersistM aQuery backend) liftNoLogging :: Monad m => ma -> NoLoggingT ma liftNoLogging = lift $ \ backend -> do  runQuery2 = withSqliteConn ":memory:" $ \backend -> do liftNoLogging (runSqlPersistM aQuery backend) liftNoLogging :: Monad m => ma -> NoLoggingT ma liftNoLogging = lift > NoLoggingT ma  runQuery2 = withSqliteConn ":memory:" $ \backend -> do liftNoLogging (runSqlPersistM aQuery backend) liftNoLogging :: Monad m => ma -> NoLoggingT ma liftNoLogging = lift 

Explanation:

  • runSqlPersistM aQuery backend - is IO-action
  • but withSqliteConn ... requires a monadic action with registration
  • so we raise the IO-action on NoLoggingT IO-action using the liftNoLogging

Finally, to run through prop_test quickCheck:

  runTest = withSqliteConn ":memory:" $ \backend -> do liftNoLogging $ quickCheck (monadicIO (prop_test backend)) $ \ backend -> do  runTest = withSqliteConn ":memory:" $ \backend -> do liftNoLogging $ quickCheck (monadicIO (prop_test backend)) 
0
source

All Articles