我正在为我的解析器编写测试,使用的方法可能不是最好的,但到目前为止一直对我有效。测试假设每个代码块都有完美定义的AST表示,如下所示:
(parse "x = 5") `shouldBe` (Block [Assignment [LVar "x"] [Number 5.0]])
然而,当我转向更复杂的案例时,出现了对更"模糊"验证的需求:
(parse "t.x = 5") `shouldBe` (Block [Assignment [LFieldRef (Var "t") (StringLiteral undefined "x")] [Number 5.0]])
我在这个例子中放了undefined
来展示我不想与解析结果进行比较的字段(它是字符串文本的源位置)。现在,解决这个问题的唯一方法是重写代码,使用shouldSatisfy
而不是shouldBe
,如果找不到其他解决方案,我就必须这样做。
您可以编写一个normalizePosition
函数,该函数将AST中的所有位置数据替换为某个固定的dummyPosition
值,然后对由相同伪值构建的模式使用shouldBe
。
如果AST非常复杂,可以考虑使用ScrapeYourBoilerplate编写此规范化。
解决此问题的一种方法是通过源位置参数化AST:
{-# LANGUAGE DeriveFunctor #-}
data AST a = ...
deriving (Eq, Show, Functor)
然后,您的parse
函数将返回一个带有SourceLocations
:的AST
parse :: String -> AST SourceLocation
当我们在上面推导出Functor
实例时,我们可以很容易地用其他东西替换源位置,例如()
:
import Data.Functor ((<$))
parseTest :: String -> AST ()
parseTest input = () <$ parse input
现在,只需在您的规格中使用parseTest
而不是parse
。