我在Haskell中使用Spock和wreq编写了一个非常简单的应用程序。我想写一些测试,但我不知道该怎么做。
该应用程序所做的只是向另一台服务器发出HTTP请求,并将JSON响应转换为人性化的消息。如果有帮助,这是代码。我想编写一个测试,在给定某个 JSON 响应的情况下断言人类友好的消息是正确的。
在 Ruby 中,我会模拟 HTTP 客户端,在本例中为wreq
来控制我得到的 JSON 响应,但我不确定如何在 Haskell 中做到这一点,甚至是否这样做。
从我从研究中收集到的信息来看,听起来类型类约束的类型变量是要走的路,这对我来说看起来像依赖注入,但我不确定如何在 Spock 和 wreq 的上下文中做到这一点。
Spock 测试教程描述了如何在IO Application
级别测试 Spock,这听起来很棒。我不确定的部分是如何"注入"模拟HTTP客户端来控制JSON响应。
任何帮助不胜感激!
如果我们想支持不同的请求方法,我们必须抽象它们。您可以让处理程序接受执行 HTTP 请求的函数作为参数,然后传递不同的函数进行测试和生产。如果您有多个相关函数,请将它们放在记录中(句柄模式(。
如果我们使用 cabal-install> 2.0(带有 new-* 命令(,另一个可能的选择是使用模块签名在测试套件和最终可执行应用程序之间切换实现。该解决方案还大量使用了 Cabal 的内部便利库功能。
基本思想是这样的:我们将 Spock 应用程序放在它自己的库中,但不要让它直接依赖于 wreq。相反,我们在同一库中声明一个签名Requests.hsig
如下所示:
signature SomeSpockApp.Requests where
import Data.Aeson (FromJSON)
data Token
doGET :: FromJSON a => String -> Token -> IO a
它定义了用于执行 HTTP 请求的高级接口。库中的代码将导入此签名。对于库中的其余代码,SomeSpockApp.Requests
只是另一个模块。
接下来,我们定义一个方便库,它将提供一个实际的模块SomeSpockApp.Requests
(与签名同名,只是现在它是一个hs
文件(。它将包含"模拟"代码。当然,doGET
的定义必须与签名兼容。
我们还定义了另一个带有另一个SomeSpockApp.Requests
模块的便利库。这个应该依赖于 wreq 并使用 wreq 的函数完成我们的签名方法。
在测试套件中,我们应该同时依赖我们的 Spock 应用程序库和模拟库。签名和模拟实现模块的名称完美排列,因此无需执行更多操作。(如果名称不匹配,我们可以在 cabal 文件中使用 mixins 节来重命名模块(。
在应用程序可执行文件中,我们应该同时依赖我们的 Spock 应用程序库和使用 wreq 的库。