私はいくつかの古いユニット テストをプロパティ ベース テスト (PBT) に置き換えようとしてscala
いscalatest - scalacheck
ます。テストしたいメソッドがある場合、単純化された状況は次のとおりです。
def upcaseReverse(s:String) = s.toUpperCase.reverse
通常、次のような単体テストを作成します。
assertEquals("GNIRTS", upcaseReverse("string"))
assertEquals("", upcaseReverse(""))
// ... corner cases I could think of
したがって、テストごとに、期待する出力を書きますが、問題ありません。さて、PBT では、次のようになります。
property("strings are reversed and upper-cased") {
forAll { (s: String) =>
assert ( upcaseReverse(s) == ???) //this is the problem right here!
}
}
すべての入力に対して true になるテストを作成しようとすると、テストでString
メソッドのロジックを再度作成する必要があることに気付きます。この場合、テストは次のようになります。
assert ( upcaseReverse(s) == s.toUpperCase.reverse)
つまり、出力が正しいことを確認するために、テストで実装を作成する必要がありました。これから抜け出す方法はありますか?私は PBT を誤解していますか?代わりに、次のような他のプロパティをテストする必要があります。
- 「文字列はオリジナルと同じ長さでなければなりません」
- 「文字列には元のすべての文字が含まれている必要があります」
- 「文字列に小文字を含めないでください」...
それももっともらしいですが、かなり不自然で明確ではないように思えます。PBT の経験が豊富な人は、ここで光を当てることができますか?
編集: @Eric のソースをたどってこの投稿にたどり着きました。(カテゴリの適用でもう一度times
): ( F#
)内のメソッドをテストするために 、まさに私が意味することの例があります:
type Dollar(amount:int) =
member val Amount = amount
member this.Add add =
Dollar (amount + add)
member this.Times multiplier =
Dollar (amount * multiplier)
static member Create amount =
Dollar amount
著者は、最終的に次のようなテストを作成します。
let ``create then times should be same as times then create`` start multiplier =
let d0 = Dollar.Create start
let d1 = d0.Times(multiplier)
let d2 = Dollar.Create (start * multiplier) // This ones duplicates the code of Times!
d1 = d2
したがって、そのメソッドをテストするために、メソッドのコードがテストで複製されます。この場合、乗算と同じくらい些細なことですが、より複雑なケースに推定されると思います。