関数型的にプログラムを書くとテストがしやすいなという話

私は中途半端に関数型言語を学んでいるところなのですが、それでもオブジェクト型言語とは異なるメリットを感じることがよくあります。

今日はその中の一つとして、「関数型言語で関数を作るとテストが作りやすい」という話をしていこうと思います。

なぜテストが作りやすいの?

関数型言語で関数を作る場合、基本的に以下の形に収まります。

単数、もしくは複数の入力を受け付けて一つのアウトプットを出す、と言った形ですね。

オブジェクト型の言語だとprint()みたいに値を返さない関数とかかなりあると思うのですが、

関数型は基本的にvoid型はあまり使わなそうな印象です*1


この形だとどのようなメリットがあるかというと「InputがXだった時、OutputがYになる」という動きになり、テスト用のXと出力結果Yを比較する値さえ用意できれば、関数Fxのテストができるようになるメリットがあります。

例えば、f(x) = x * 2 をテストしたい場合はf(2)の時4になるかをチェックすればテストできます。

注意! 入力が同じなら出力も同じ関数でないとテストできない

ただ、関数を作る際、注意があります。「InputがXだった時、Outputが必ずYになる」ということを保証できる関数である必要があります。このようにしないとテストがしにくい関数になってしまいます。

例えをみてみましょう。

ある場所Xを入力すると今日の天気を出力する関数を作りました。

この関数は、前述の関数の基本的な形に当てはまる構成をしております。が、テストは非常にしにくい関数です。

なぜなら実行するタイミングで出力が変わってしまうからです。


今ブログを書いている時点で私の現在地で関数を実行したら「晴れ」と返すでしょう。

では、何日か後に同じ関数を実行したらどうなるでしょうか?

同じく「晴れ」を返すかもしれませんが、「くもり」かもしれませんし、「雪」だったり「雨」かもしれません。

このように同じ関数でも結果が変わってしまうと、出力のチェックができなくなります。

そうするとテストをしようにも「何かしら値が返ってきてる」とか「晴れ、曇り、雨、雪のいずれかが返ってくる」と言った大雑把なテストになって、何をテストしてるかわからないテストになりがちです。


このような関数をテストしやすくする場合は、場合によって変わる部分を切り出して入力にするとテストできるようになったりします。

例えば、前述天気関数でしたら、時刻を新しい入力にすれば、テストのできる関数になります。


本日はここまで、またお会いしましょう。

*1:勉強で使用している本ではREPL形式で実行されるためか、勝手に変数がアウトプットされているような形でした。標準出力をどのように行うのかは今後勉強を進める上で調べてみようと思います