乱数を生成する関数があります。受け入れテストの際に、これを既知の数値を生成するものに置き換えたいと考えています。
オブジェクト指向言語では、依存性注入を使用し、テスト セットアップでこのコンポーネントを別の方法で接続するだけです。関数型言語でこれを行うことができる唯一の方法は、依存関係を必要とする関数に到達するまで、ルートからプログラムを介して依存関係を渡すことです (ここでは「カメがずっと下にいる」というのが正しい言い回しですか?) .
より良い方法はありますか?
乱数を生成する関数があります。受け入れテストの際に、これを既知の数値を生成するものに置き換えたいと考えています。
オブジェクト指向言語では、依存性注入を使用し、テスト セットアップでこのコンポーネントを別の方法で接続するだけです。関数型言語でこれを行うことができる唯一の方法は、依存関係を必要とする関数に到達するまで、ルートからプログラムを介して依存関係を渡すことです (ここでは「カメがずっと下にいる」というのが正しい言い回しですか?) .
より良い方法はありますか?
多数のオプションがあります-関数を渡す、依存性注入メカニズムを使用する(標準の.NETライブラリの多くはF#で動作しますが、F#固有の軽量ツールもいくつかある場合があります)、またはモナドを使用して暗黙的に状態を渡します。
ただし、実行時に本番セットアップとテストセットアップのどちらかを選択する必要がありますか?いいえの場合は、テスト用に別の方法で実装する関数を別のファイルに移動し、プロジェクトの2つの異なるビルドを作成できます。
これは純粋な解決策ではないかもしれませんが、非常に単純で(Random.Test.fs
代わりに使用するだけですRandom.Runtime.fs
)、機能も優れています。単一(または複数)の関数の異なる実装を提供するだけで、残りのコードはそれらを使用します。
おそらく、次のようなものがあります。
let generateRandomNumber =
let generator = new System.Random()
fun () -> generator.Next()
let addFiveToRandomNumber() =
let next = generateRandomNumber()
next + 5
addFiveToRandomNumber
テストしたい関数はどこにありますか。
問題の適切な解決策、および F# での一般的な適切な方法は、純粋な関数と不純な関数を解きほぐすことです。
let generateRandomNumber =
let generator = new System.Random()
fun () -> generator.Next()
let addFiveToGeneratedNumber generator =
let next = generator()
next + 5
let addFiveToRandomNumber() = addFiveToGeneratedNumber generateRandomNumber
テストしたい関数は ですaddFiveToGeneratedNumber
。たとえば、addFiveToGeneratedNumber (fun () -> 1)
常に 6 を返す必要がありgenerateRandomNumber
ますaddFiveToRandomNumber
。
したがって、ここでの解決策は「依存関係を渡す」ことですが、ルートから来る必要はありません。
純粋な関数型言語でこれを行う唯一の方法は、状態を最後までスレッド化することです。F# は不純なので、オブジェクト指向で行う一般的な方法で行うことができます。しかし、あなたがプラグマティクスについて尋ねているのか、それとも機能的なデザインが問題にどのように取り組んでいるかについて尋ねているのかはわかりません.