2

式が検出されたときに失敗する必要がある Haskell で単体テストを作成するundefinedのは少し注意が必要です。HSpecで次のことを試しました:

module Main where

import Test.Hspec
import Control.Exception (evaluate)

main :: IO ()
main = hspec $ do
  describe "Test" $ do
    it "test case" $ do
      evaluate (take 1 $ map (+1) [undefined, 2, 3]) `shouldThrow` anyException

無駄に。それは私を報告しますdid not get expected exception: SomeException

同じ式を REPL で評価すると、次のようになります。

[*** Exception: Prelude.undefined
CallStack (from HasCallStack):
  error, called at libraries\base\GHC\Err.hs:79:14 in base:GHC.Err
  undefined, called at <interactive>:2:20 in interactive:Ghci1
4

1 に答える 1

4

問題は、式を NHまたは WHNF 1evaluateに強制しないことです。GHCi で試してみてください。エラーは発生しません。貼り付けたときにそうする唯一の理由は、GHCi が取得した結果を出力しようとするためであり、そのために最終的に式を評価しようとします。x <- evaluate (take 1 $ map (+1) [undefined, 2, 3])evaluate (take 1 $ map (+1) [undefined, 2, 3])

サンクがどれだけ評価されたかを確認したい場合は:sprint、GHCi でいつでも使用できます。

ghci> x <- evaluate (take 1 $ map (+1) [undefined, 2, 3])
ghci> :sprint x
x = [_]

ご覧のとおり、evaluateは. 簡単な修正は、 を使用して、調べているものを通常の形式に評価することです。xundefinedforce

import Test.Hspec
import Control.Exception (evaluate)
import Control.DeepSeq (force)

main :: IO ()
main = hspec $ do
  describe "Test" $ do
    it "test case" $ do
      evaluate (force (take 1 $ map (+1) [undefined, 2, 3] :: [Int])) 
        `shouldThrow` anyException

force引数が完全に評価されるまで、サンクの評価をトリガーできます。NFDataそれには(「通常の形式のデータ」を表す)制約があることに注意してください。そのため、データ構造を導き出しGenericていることに気付くかもしれません。NFData


1引数をWNHFにプッシュevaluate することを指摘してくれた@AlexisKingに感謝しhead $ map (+1) [undefined, 2, 3]ます。これがエラーをトリガーする理由です。の場合take、それだけでは不十分です。

于 2016-12-14T21:06:30.730 に答える