5

users-gen1 人以上のユーザーのグループを生成するgenerator があるとします。user-actions-genそして、1 人以上のユーザーのシーケンスを取得し、それらのユーザーが実行する一連のアクションを生成する別のパラメーター化されたジェネレーターが呼び出されます。

(def user-gen 
 ;; generates a user
 ...)

(def users-gen 
 ;; sequences of 1 or more users 
 (gen/such-that not-empty (gen/vector gen/users))

(defn user-actions-gen [users]
  ;; a action performed by some user from the `users argument
  ...)

users-gen によって生成された単一のユーザー シーケンスに対して単一のアクションを生成したい場合は、単純です。users-gen を直接 user-actions-gen に生成/バインドするだけです。

ただし、同じ一連のユーザーから多くのアクションを生成したいと考えています。私がこの問題を抱えているのは、基本的に「これが状態です。任意のランダムなアクションを入力させて、アクションを状態に適用させて、状態がまだ有効であることを確認させてください。これをすべてのアクションに対して実行してください。 " 次のコードがあります。

(defspec check-that-state-is-always-valid
  100
  (let [state-atm (atom {})]
    (prop/for-all
     [[actions users]
      (gen/bind users-gen
                (fn [users]
                  (gen/tuple
                   (gen/vector (user-actions-gen users))
                   (gen/return users))))]
     (doseq [action actions
             :let [state (swap! state-atm state-atm-transform-fx action)]]
       (is (state-still-valid? state))))))

この種の作品。問題は次のとおりです。

  1. 最初のエラーで停止するのではなく、doseq を完全に評価しているようです。
  2. ちょっと間違っているように見えます。コードはいたるところにあり、それが何をするのか完全には明らかではありません。
  3. user-action-gen は、users-gen の実現されたユーザーの値ではなく、users-gen のジェネレーターを使用する必要があるようです。これは構成可能性に役立ちますか? users-gen はおそらく他のジェネレーターに役立つため、それらをまとめたくないことに注意してください。

では、要約します。1 つのジェネレーターから生成された単一の値を取得し、それを引数として複数のジェネレーターに渡しています。より魅力的/エレガントな方法でこれを行うにはどうすればよいですか?

4

2 に答える 2

2

test.check( )の最新バージョンをチェックアウトすることをお勧めし0.9.0ます。ジェネレーターの名前空間にが含まれるようletになり、ジェネレーターの作成が簡単になりました。

https://github.com/clojure/test.check/blob/master/src/main/clojure/clojure/test/check/generators.cljc#L1452

これの欠点は、これを直接実行できないことですprop/for-all(明らかに後方互換性の理由による)。

別の方法としてお勧めするのは、 test.chuckを使用することです(現在のメンテナーによって書かれていtest.checkます)。とfor-all同じようにバインディング フォームが機能するgenerators/letがあります。これは私が見つけた最もクリーンなアプローチであり、非常にうまく機能します。

于 2016-03-06T14:58:03.217 に答える
1

あなたが現在行っていることに 2 つの主な変更を加えます。

  1. gen/bind暫定的に名前が付けられた新しいジェネレーターにインラインを引き出します(名前と一致するように結果のとusers-and-actions-genの順序を入れ替えたことにも注意してください):usersactions

    (def users-and-actions-gen
      (gen/bind users-gen
                (fn [users]
                  (gen/tuple
                   (gen/return users)
                   (gen/vector (user-actions-gen users))))))
    
  2. アトムを必要としないものをテストするために使用しないでください。代わりに、状態の遅延シーケンスを生成し、それらすべてが探しているプロパティを持っていることをテストするだけです。そうすれば、探している短絡プロパティを持つだけでなく、うまく読み取れます。

    (defspec check-that-state-is-always-valid
      100
      (prop/for-all [[users actions] users-and-actions-gen]
        (is (every? state-still-valid? 
                    (reductions (fn [state action]
                                  (state-atm-transform-fx state action))
                                {} actions)))))
    

これらの 2 つの変更を除けば、現在行っていることを本当に改善できるかどうかはわかりません。あなたusers-and-actions-genはかなり具体的だと思います。少し一般化できますが、一般化がそれほど役立つかどうかはわかりません(本質的に制限付きになりますbind)。私が上で提案したことは、あなたの問題 (1) と (2) を解決するはずですが、(3) は本当に問題ではないと思います。

于 2014-06-07T12:54:41.287 に答える