📝Clojure: テスト(testing/TDD)

📝Clojure: テスト(testing/TDD)

January 28, 2023

clojure.test #

Clojureの標準ライブラリ.

  • deftest: テスト定義.
  • is: アサーション.
  • are: isをテンプレに従って複数書くマクロ.
  • testing: 引数を取り連続したアサーションを入れる. グルーピングやドキュメント用.
    • BDDのように期待するべき仕様をかける.
  • use-fixtures: setup/teardownの制御.

テストフィクスチャ(Setup/Teardown/use-fixtures) #

テストの前処理(Setup), 後処理(Teardown)はFIXTURESとしてClojuredocに方法が記載されている. 基本的にはfixture関数を自前で関数を書いて呼び出す.

https://clojuredocs.org/clojure.test

そして, 自作のfixtureを順番に呼び出す関数がuse-fixturesとして提供されている. :once/:eachのオプション引数によって, 呼び出しの挙動が変わる.

https://clojuredocs.org/clojure.test/use-fixtures

(defn my-test-fixture [f]
	(create-db)
	(f)
	(destroy-db))

;; namespaceのtest実行で一度呼ばれる.
(use-fixtures :once my-test-fixture)

;; namespaceのtest実行で毎回呼ばれる.
(use-fixtures :each my-test-fixture)

ポイントはnamespace単位であるところ(!= testing単位). いちおう改善の提案はされているようで, 将来はdeftest単位でfixtureが設定できるようになるかもしれないが, 現時点では外部ライブラリを利用する.


References #

Clojureテストランナー #

一連のテストケースを実行する仕組み.

  • Emacs CIDER: Emacsをつかっているならばファーストチョイス.
  • kaocha: モダンなテストランナー.

Clojure テストライブラリ #

モックやスタブをサポートしているもの.

🔧nubank/mockfn #

📝Nubankの開発したMocking用フレームワーク.

Build a bank: Nubank with Edward Wibleでの, I/O部分にしか副作用させないように書けるファンクショナルなClojureは超良かったよというのはこのライブラリのことか???

verifying #

モックが呼ばれた回数をチェックする. 以下の例は1回だけ呼ばれたことをチェック.

(testing "verifying"
  (verifying [(one-fn :argument) :result (exactly 1)]
    (is (= :result (one-fn :argument)))))

spying #

スタブの機能にmatterを組み合わせてテストスパイ的に振る舞う.

ポイントはassertに失敗すると例外が上がる. prividingを使えばいい. 無名関数は(pred (fn.. ))のシンタックスシュガー.

(deftest update-order-test
  (providing
   [(sut/handle-order (any)
		      (any)
		      (fn [m] (= (:side m) :buy))
		      (any)) :mocked]
   (is (= :mocked
	  (sut/update-order! {:ex ex} {:side-id :buy})))))

mockfn/matchers #

`mockfn.matchers`に含まれるもので, 仮引数や戻り値の検証につかう. mockfnに組み込みのマッチャーと外部マッチャーがある.

外部マッチャーは pred の引数に関数を渡す. スタブの引数に関数を渡すとそれは(pred f)のシンタックスシュガーになる. または, 🔧nubank/matcher-combinatorsをつかうと高度な比較ができる.

https://github.com/nubank/mockfn/blob/master/doc/documentation.md#built-in-matchers

tips: 高階関数でわたした関数のmockができない #

調査中… たぶんできない.

tips: プロトコルに実装した関数のmockはthisを渡すと失敗する #

ちょっとした注意点かもしれない. mockfnでProtocolのmockはできるが, プロトコルの実装の関数にthisをわたすとモックが効かないでthisの関数実装を呼び出すので, 適当なオブジェクトを渡さないといけない.

最近Clojureでテストを書くときに使っているライブラリをふたつ紹介します - Uzabase for Engineers

🔧nubank/matcher-combinators #

複雑なデータ構造を比較する. 🔧nubank/mockfnのmatcherとコンボで使える.

Clojure: TDD #

🔖TDD

ClojureテストTopics #

テストファイルは (hogehoge-test.clj)の慣習に従う #

テストファイルはtestディレクトリ配下に置く. そして階層はsrcと同じにして, ファイル名をhogehoge-test.cljにする.

Name your ns yourproject.something-test, a file which usually lives in test/yourproject/something_test.clj (or .cljc, cljs).

deftestでテストを定義して, テスト名はhogehoge-testというsuffixにする.


ものすごくハマった記憶として, ソースファイルとテストファイルを同じ名前とnamespaceで宣言した結果, あるソースファイルからテストファイルをrequireしてエラーして2時間が経過した. 悲しみを忘れない.


The Clojure Style Guide - testing

CIDERのtesting補助機能 #

Emacs CIDERのテスト補助機能.

  • C-c C-t l: ロードされたすべてのテスト実行.
  • C-c C-t n: namespaceのテスト実行.
  • C-c C-t t: 特定のテスト実行(at-point).
  • projectile-toggle-between-implementation-and-test, テストと実装をtoggle
  • projectile-find-implementation-or-test-other-window, テストと実装をtoggle

ref. https://docs.cider.mx/cider/testing/running_tests.html

ClojureにTDDは必要なのか? #

Clojureは動的型付け言語であることを忘れてはいけない…


Clojure並列テスト(Parallelising testing) #

わたしはこの意味するところをまだ理解していない. いちおうTopicのエントリポイントのみ作成.

References #

👉Related #