• 作成:

doctestを実行するようにしたのですが, 全部指定するとTravis CIが通らない

これまでhaddock形式のコメントで使い方を書く時にdoctestの形式でコメント書いていました. しかし, 実際doctestは実行していませんでした. いい加減実行してテストしておこうと思ったので導入しました.

Travis CIのコマンドを変えずにテストを自動実行して欲しいのでコマンドラインでの実行はやりたくないですね.

Stack(Cabal)と連携して実行するようにしたいです.

package.yamlに書くことにします.

doctest-discoverを導入してみました

しかし公式の導入方法だとだと引数にソースファイルを全指定する必要があるようですね. (勘違い) それはファイル指定に漏れが発生しそうなのでイヤですね.

そこでdoctest-discoverを使うと, ファイル一覧を自動生成してくれるようですね.

package.yamlに以下のように指定します.

tests:
  doctest:
    main:         doctest-driver.hs
    ghc-options:
    - -fwarn-tabs
    - -threaded
    - -rtsopts
    - -with-rtsopts=-N
    dependencies:
    - application
    - doctest
    - doctest-discover

ここでsource-dirs: testと指定したい所ですが, 既にHspecを導入しているため以下のエラーが出ます.

…/test/Spec.hs:2:8: error:
    File name does not match module name:
    Saw: ‘Main’
    Expected: ‘Spec’

とりあえずのワークアラウンドとしては, 指定せずにトップディレクトリにdoctest-driver.hsを置けば問題なくなります.

doctest-driver.hsには公式通り以下を書きます.

{-# OPTIONS_GHC -F -pgmF doctest-discover #-}

わざと間違ったコメントを書いてエラーを吐くことを確認.

…:117: expression `foo (-2.5)'
expected: -2
 but got: -3
Examples: 7  Tried: 7  Errors: 0  Failures: 1

全部指定すると遅すぎる

これだとやたらとテスト実行が遅いんですよね. 手元のマシンで32秒はかかってしまいます.

手元だと問題ないのですが, Travis CIが毎回相当遅くなるのは許容できないですね. 相当時間かかってます. Travis CIの仮想マシンはCPUがかなり貧弱ですからね.

まあ時間がかかってもちょっと待てば良いかと思ってたら

No output has been received in the last 10m0s, this potentially indicates a stalled build or something wrong with the build itself.
Check the details on how to adjust your build configuration on: https://docs.travis-ci.com/user/common-build-problems/#Build-times-out-because-no-output-was-received

と言われてしまいました. 何も出力せずに10分沈黙するのはダメみたいですね.

これを改善するために, Template Haskellでコードを大量に自動生成するモジュールをテスト対象から除外しようとしました. しかしドキュメントを見て設定してもさっぱりうまくいきませんでした. テストがあるモジュールを除外指定してみても, テスト認識してしまっていて除外設定がうまく動いてないことがわかります.

どういうことだと思ってdoctest-discoverやめて自分で書いてみたら, doctestは-isrcのようにディレクトリが指定されていると, import先を自動で見ていって全てテスト実行することがわかりました.

-isrcを指定しないと, doctestはcabalのdependenciesを見ないため, 直接依存していないパッケージも見に行ってしまって, import Foundationのようなimportがあると, どっちを参照すれば良いのかわからなくなってエラーになるようです. 他にも孤立インスタンスをちゃんと参照できずにエラーになるようですね.

簡単な解決は無理そう

仕方がないので-isrcを指定せずに, doctestのコメントが存在する軽いモジュールだけをdoctestに渡すようにしました.

速度を気にしなければちゃんと全体を指定してもdoctestは動いてくれるのですが. このような形で部分指定するようになったのは遺憾です.

doctestに--fastオプション付けたら少しだけ早くなりますが, プロジェクト全体をカバーするようなモジュール(Yesodの場合はsrc/Application.hs)を指定すると, やはり許容できない遅さになります.

最終的にdoctest呼び出しは以下のようになりました.

main = doctest ["--fast", "UseDoctestModule.hs"]

今回はdoctestを使っているモジュールが限られていたので問題ありませんでしたが, 大規模になると無理になってしまうので, 問題が避けられない場面になったら高速化に取り組みたいですね.