両方ともかなり良いようです。特に Web アプリケーションのテストに関して、各ライブラリが特に優れている点と欠けている点を理解したいと思います。
5 に答える
私は speclj を使用したことがなく、Midje の最初の作成者でした。他の人が言及していない点の 1 つは、Midje が関数型言語とオブジェクト指向言語の違いを利用しようとしているということです。
1 つの違いは不変性です。ほとんどの関数は、含まれている状態ではなく、入力のみに依存するため、それらについて作成する真実のステートメントの種類は、オブジェクト指向の対応するものとは異なります。OO テストでは、「この履歴とこれらの入力が与えられた場合、このメソッドはこれとこれを生成する」という形式の例を作成します。
関数型言語の例は、「これらの入力が与えられると、この関数はこれなどを返す」という単純なものになるように思われます。しかし、それはまったく正しいとは思いません。システムの他の機能は、状態/履歴に類似した役割を果たしていると思います。それらは、知的制御を得ようとしているものの1つです。関数とその関係は、テストで明確に考えるのに役立つものです。
そのため、Midje は、甘い開発プロセスには次のように言うことが含まれるという仮定の下で書かれています。
- この関数の何が真実でありたいですか? システムの世界で、この機能が何をするかを考える良い方法は何ですか?
- それを行う過程で、他にどのような関数が役に立ちますか?--ドメインの重要な部分をキャプチャします---そして、それらについてどのような真実のステートメントを作成したいですか?
そして、典型的なモックイスト スタイルでは、大まかにトップダウンまたはアウトサイド インで開発し、間違いから回復したり、より良いアイデアを思いついたりする際に、避けられない反復を可能にします。
最終的な結果は、関数の相互関係がテストまたは (Midje が呼ぶように) 関数とそれらが依存する関数に関する「事実」によって文書化された、関数の大きな山になります。さまざまな人が、Midje には Prolog/ロジック プログラミングの感覚があるとコメントしていますが、それは偶然ではありません。いつものように、テストは例ですが、Midje はそれらをより真実のステートメントのように読ませようとします。これが、実際に革新的な唯一の機能であるメタ定数の正当な理由です。それらの例を次に示します。
(fact "right changes the direction, but not the position"
(right (snapshot north ...position...)) => (snapshot west ...position...)
(right (snapshot east ...position...)) => (snapshot north ...position...)
(right (snapshot south ...position...)) => (snapshot east ...position...)
(right (snapshot west ...position...)) => (snapshot south ...position...))
right
この場合、実際の位置は、決して変化しないことを除いて、関数の真とは無関係です。メタ定数の考え方は、テストで明示的に述べられていることを除いて何も知られていない値であるということです。テストでは、何が本質的で何が付随的かを判断するのが難しいことがよくあります。これには、理解、保守性など、多くの悪影響があります。メタ定数は明確さを提供します。3
値が keyの値を含むマップまたはレコードであることが重要な:a
場合は、明示的に次のように言います。
(fact
(full-name ..person..) => "Brian Marick"
(provided
..person.. =contains=> {:given-name "Brian", :family-name "Marick"}))
このテストは、人々にとって何が重要かを明確に示し、重要でないこと (2 つの名前以外) も明確にします。
数学的に言えば、Midje は「for all x where x...」のようなステートメントを作成できるようにしようとしていますが、定理の証明者というよりはテスト ツールでもあります。
このアプローチは、 Growing Object-Oriented Softwareで説明されている種類の「ロンドン スタイル」のモックを多用した TDD に触発されたもので、Ruby コードを記述する際に私が通常使用するアプローチです。しかし、それは説明するのが難しい方法で、かなり異なる感触を持っていることが判明しました. しかし、単なるwith-redefs
.
要するに、Midje は、OO TDD の単なるポートではない、関数型 TDD のスタイルを見つけようとする試みの一部であるということです。これも汎用ツールになろうとしていますが、やや独断的なソフトウェアです。エイブラハム・リンカーンが言ったように、「この種のものが好きな人は、これが好きだと感じるでしょう。」
私は間違いなくSpecljに行きます。
Speclj は簡単に統合して使用できます。その構文は、Midje のものより派手ではありません。Speclj は RSpec に基づいており、Clojure の特異性を失うことなく、Ruby プログラマーが慣れているすべての快適さを提供します。
Speclj の自動ランナーは素晴らしいです。
lein spec -a
しばらく使用すると、手動でテストを実行しなければならなかったときに、どのように作業を完了したのか不思議に思うでしょう。
単純に with-redefs を使用できるため、モッキングは問題になりません。@rplevy の Speclj での例は次のようになります。
(ns foo.core-spec
(:require [speclj.core :refer :all ]
[foo.core :as base]))
(describe "Core"
(it "contrives 100"
(let [message-params (atom nil)]
(with-redefs [base/timestamp (fn [] 1350526304739)
base/important-message #(reset! message-params [%1 %2])]
(should= {:x 100 :timestamp 1350526304739} (base/contrived 100))
(should= 100 (first @message-params))))))
モックに対するこの必要最小限のアプローチは的を射ています。誤指示なし。
Web アプリのテストに関しては、Speclj は問題なく動作します。実際、Speclj サポートは Joodo に組み込まれています。
免責事項: 私は Speclj を書きました
Midje を使用する最大の利点は、物事のすべての部分をテストすることなく、物事をテストするための焦点を絞った抽象化を提供することです。
補助関数を呼び出してタイムスタンプを生成したり、データベースまたはメッセージ キューに何かを入れたり、API 要求を作成したり、何かをキャッシュしたり、何かをログに記録したりする関数がある場合、これらの世界に関与する関数呼び出しが発生したことを知りたい (ただし、実際にそれらを実行することは、テストしている関数とは無関係であり、呼び出された関数は多くの場合、独自の単体テストを行う価値があります。
コードにこれがあるとします:
(defn timestamp [] (System/currentTimeMillis))
(defn important-message [x y] (log/warnf "Really important message about %s." x))
(defn contrived [x & y]
(important-message x y)
{:x x :timestamp (timestamp)})
midje でテストする方法は次のとおりです。
(ns foo.core-test
(:require [midje.sweet :refer :all]
[foo.core :as base]))
(fact
(base/contrived 100) => {:x 100 :timestamp 1350526304739}
(provided (base/timestamp) => 1350526304739
(base/important-message 100 irrelevant) => anything :times 1))
この例は midje で何ができるかを簡単に垣間見るだけですが、midje が得意とすることの本質を示しています。ここで、表現に必要な余分な複雑さがほとんどないことがわかります。
- 関数が生成するもの (タイムスタンプ関数が生成するものは、関数を呼び出すたびに異なるという事実にもかかわらず)、
- タイムスタンプ関数とロギング関数が呼び出されたこと、
- ロギング関数が 1 回だけ呼び出されたこと、
- ロギング関数が予期された最初の引数を受け取ったこと、および
- 受け取った 2 番目の引数が何であったかは気にしません。
この例で私が言おうとしている主なポイントは、すべてをテストしようとするのではなく、複雑なコードのテストを表現する非常にクリーンでコンパクトな方法であるということです (複雑とは、分離可能な部分が埋め込まれていることを意味します)。一斉に。すべてを一度にテストすることには、その役割があります。つまり、統合テストです。
私は積極的に midje を使用しているので偏見があることは認めますが、speclj だけを見たことがありますが、私の感覚では、類似の Ruby ライブラリを使用したことがあり、テストに対するその考え方が理想的であると考える人にとって、speclj はおそらく最も魅力的です。経験。これは、テスト フレームワークを選択するための完全に立派な理由であり、うまくいけば他の人がコメントできるように、おそらく他にも良い点があるでしょう。
Midje は、スタブとモックを表現するための DSL を作成するのが特に得意だと思います。スタブとモッキングに関心があり、それを頻繁に使用したい場合は、Speclj よりも Midje を選択します。これは、slagyr が回答で提供するアプローチよりも簡潔なこれらのタイプのテストを表現するための抽象化があるためです。
より軽量なアプローチが必要な場合の別のオプションは、clojure.test で使用することを目的としたConjure stubbing/mocking ライブラリです。
Speclj が優れているところは、RSpec によく似ていて、'describe' と 'it' が含まれていることです... Midje はネストされたファクトを実際にサポートできますが、Speclj ほどエレガントではありません。
免責事項: 私は Midje and Conjure の寄稿者です。:)
Speclj よりも Midje をお勧めし
ます。
また、Midje の構文の方が優れています。
(foo :bar) => :result compared to (should= (foo :bar) :result)