如何在Yesod项目中结合Sqlite使用Hspec/Yesod.Test并解决类型匹配错误
问题原因
你遇到的类型报错核心来自两个不匹配:
yesodSpecWithSiteGeneratorAndArgument要求传入的站点生成器类型为a -> IO App,即需要接收一个自定义参数,且返回包在IO中的App实例。你当前的代码既没有处理传入参数,最后也直接返回了App值而非IO包装的App。- 绝大多数测试场景不需要传递额外自定义参数,直接用更简单的
yesodSpecWithSiteGenerator即可,它只要求生成器返回IO App。
修改方案
无额外参数的常用版本(推荐)
shortblitoWebServerSpec :: Spec -> Spec shortblitoWebServerSpec = yesodSpecWithSiteGenerator $ withSqlitePool ":memory:" 1 $ \pool -> do let app = App { appLogLevel = LevelWarn , appStatic = shortblitoWebServerStatic , appConnectionPool = pool , appGoogleAnalyticsTracking = Nothing , appGoogleSearchConsoleVerification = Nothing } flip runSqlPool pool $ runMigration migrateTables pure app -- 把App实例包装为IO App,符合类型要求
需要传递自定义测试参数的版本
如果你确实需要给测试用例传递自定义配置,再用带参数的版本:
shortblitoWebServerSpec :: SpecWith App -> SpecWith a shortblitoWebServerSpec = yesodSpecWithSiteGeneratorAndArgument $ \customArg -> -- 接收传入的自定义参数,可用于调整App配置 withSqlitePool ":memory:" 1 $ \pool -> do let app = App { appLogLevel = LevelWarn , appStatic = shortblitoWebServerStatic , appConnectionPool = pool , appGoogleAnalyticsTracking = Nothing , appGoogleSearchConsoleVerification = Nothing } flip runSqlPool pool $ runMigration migrateTables -- 你可以在这里根据customArg修改App配置,或者插入测试数据 pure app
注意事项
- 内存SQLite数据库仅对同一个连接可见,所以测试用的连接池大小保持为1即可,避免出现表找不到的问题
- 每次测试用例执行都会重新创建内存数据库,不同用例之间数据不会互相干扰
- 如果需要提前插入测试数据,直接在
runMigration语句后追加对应的SQL操作即可
内容的提问来源于stack exchange,提问作者The Oddler
相关产品推荐
相关产品推荐

