3

関数が Haskell HSpec で呼び出されたことを確認することは可能ですか?

データを変換する2 つの関数foobarがあると仮定します。

foo :: Stuff -> Stuff
bar :: Stuff -> Stuff

そして 、2 番目の引数として「f」または「b」を受け取ったかどうかに応じて、スタッフにfooまたはbarを適用し、適用された関数の結果を返す関数があります。

apply :: Stuff -> Char -> Stuff

そして、私のテストでは、各関数 foo と bar を包括的にテストしましたが、その影響をapplyでテストしたくありません。

関数 foo または bar が呼び出されたことを確認することはできますか? 適用するために渡される引数に応じて?

4

2 に答える 2

3

「私はOOP言語のようにもっとTDDを考えています.Haskellでそのようなことは可能ですか?」

より良い質問は、「Haskell でそのようなことは必要ですか?」です。;-)

[それはあなたが実際に尋ねた質問ではないことに気づきました。この回答は無視してかまいません。]

OO 言語では、他のオブジェクトと対話して仕事を遂行するオブジェクトを構築します。そのようなオブジェクトをテストするために、偽のオブジェクトの束を構築し、実際のオブジェクトを偽のオブジェクトに接続し、テストしたいメソッドを実行し、予想される入力で偽のメソッドを呼び出すことをアサートします。

Haskell では、関数を記述します。純粋な関数が行う唯一のことは、何らかの入力を受け取り、何らかの出力を生成することです。したがって、それをテストする方法は、単に実行し、既知の入力を与えて、既知の出力を返すことを確認することです。それを行う過程で他のどの関数を呼び出すかは問題ではありませ。私たちが気にするのは、答えが正しいかどうかだけです。

特に、OOP で通常これを行わない理由は、何らかの任意のメソッドを呼び出すと、ディスク ファイルの読み取りまたは書き込み、ネットワーク接続の開始、データベースや他のサーバーとの通信などの「実際の作業」が発生する可能性があるためです。コードの一部をテストしているだけで、どこかの実際のネットワーク サーバーでデータベースが実行されているかどうかにテストを依存させたくありません。コードのほんの一部をテストしたいだけです。

Haskell を使用すると、実世界に影響を与える可能性のあるものを、データ変換だけを行うものから分離できます。メモリ内のデータを変換するだけのものをテストするのは、とても簡単です! (実世界と相互作用するコードの部分をテストすることは、一般的にはまだ難しいです。しかし、うまくいけば、それらの部分は現在非常に小さいものです。)

選択された Haskell テスト スタイルは、プロパティ ベースのテストのようです。たとえば、方程式を解く関数がある場合、100 個の方程式をランダムに生成する QuickCheck プロパティを記述し、それぞれについて、返された数が実際に元の方程式を解くかどうかをチェックします。これはほんの一握りのコードで、知りたいことのほぼすべてを自動的にテストします。(ただし、完全ではありません。「ランダムに」選択された方程式が、関心のあるすべてのコード パスを実際にテストすることを確認する必要があります。)

于 2014-08-07T16:55:32.140 に答える
0

(正確には Haskell ではありませんが、近いです。)

fooP = point . foo
-- testable property: forall s. foo s = runIdenity $ fooP s

barP = point . bar
-- similar testable property

fooAndWitness :: Stuff -> Writer String Stuff
fooAndWitness = fooM >> tell "foo"
-- testable property forall s. (foo s, "foo") = runWriter $ fooAndWitness s

barAndWitness :: Stuff -> Writer String Stuff
barAndWitness = barM >> tell "bar"
-- similar testable property

applyOpen :: Pointed p => (Stuff -> p Stuff) -> (Stuff -> p Stuff) -> Stuff -> Char -> p Stuff
applyOpen onF _   x 'f' = onF x
applyOpen _   onB x 'b' = onB x
applyOpen _   _   x _   = point x
-- semi-testable property (must fix p):
-- forall f b s c. let a = applyOn f b s c in a `elem` [f s, b s, point s]
-- In particular, if we choose p carefully we can be, at least stochastically,
-- sure that either f, b, or neither were called by having p = Const [Int], and running several tests
-- where two random numbers are chosen, `f _ = Const $ [rand1]`, and `b _ = Const $ [rand2]`
-- and verifying we get one of those numbers, which could not have been known when applyOpen was written.

applyM = applyOpen fooM barM
-- similar testable property, although but be loose the "rigged" tests for variable f/b, so
-- some of our correctness may have to follow from the definition.

apply = (runIdentity .) . applyM
-- similar testable property and caveat

PointedFunctor と Applicative の間に収まる型クラスであり、 orpointと同じセマンティクスを提供します。パラメトリック性から従うのは法律だけです。purereturn(. point) . fmap = (point .)

于 2014-08-07T01:11:59.407 に答える