Sebagai latihan saya ingin menerapkan pohon 2-3 jari. Ini akan menjadi kesempatan sempurna untuk mencoba pengujian berbasis model FsCheck. Saya memutuskan untuk mencoba versi eksperimental yang lebih baru.
Sejauh ini saya hanya mengkodekan satu perintah untuk mesin uji karena saya sudah gagal dalam membuat perintah tersebut berfungsi—di sisi lain hal ini membuat postingan menjadi singkat. Kode selengkapnya tersedia di GitHub.
open CmdQ
open Fuchu
open FsCheck
open FsCheck.Experimental
type TestType = uint16
type ModelType = ResizeArray<TestType>
type SutType = FingerTree<TestType>
let spec =
let prepend (what:TestType) =
{ new Operation<SutType, ModelType>() with
override __.Run model =
// Also tried returning the same instance.
let copy = model |> ResizeArray
copy.Insert(0, what)
copy
override __.Check(sut, model) =
let sutList = sut |> Finger.toList
let newSut = sut |> Finger.prepend what
let newSutList = newSut |> Finger.toList
let modelList = model |> Seq.toList
let areEqual = newSutList = modelList
areEqual |@ sprintf "prepend: model = %A, actual = %A (incoming was %A)" modelList newSutList sutList
override __.ToString() = sprintf "prepend %A" what
}
let create (initial:ModelType) =
{ new Setup<SutType, ModelType>() with
override __.Actual () = initial |> Finger.ofSeq
override __.Model () = initial //|> ResizeArray // Also tried this.
}
let rndNum () : Gen<TestType> = Arb.from<uint16> |> Arb.toGen
{ new Machine<SutType, ModelType>() with
override __.Setup =
rndNum()
|> Gen.listOf
|> Gen.map ResizeArray
|> Gen.map create
|> Arb.fromGen
override __.Next _ = gen {
let! cmd = Gen.elements [prepend]
let! num = rndNum()
return cmd num
}
}
[<Tests>]
let test =
[spec]
|> List.map (StateMachine.toProperty >> testProperty "Finger tree")
|> testList "Model tests"
Yang saya pahami adalah ini: Operation<_>.Run
dijalankan dua kali untuk membangun ResizeArray
dari satu elemen dengan satu elemen. Kemudian Operation<_>.Check
dijalankan dua kali dengan nomor yang sama untuk dimasukkan ke dalam satu elemen FingerTree<_>
.
Yang pertama dari dua operan. Pohon elemen tunggal masuk, penambahan menjadikannya pohon dua elemen (benar) yang sebanding dengan model setelah perintah pertama.
Perintah kedua selalu gagal. Check
dipanggil dengan ResizeList
yang lebih besar (sekarang 3 elemen) tetapi Pohon elemen tunggal yang sama seperti pada perintah pertama. Menambahkan satu elemen lagi tentu saja tidak akan membuatnya menjadi ukuran 3 dan pengujiannya gagal.
Saya berharap saya perlu mengembalikan model yang diperbarui dari Check
agar perintah yang akan datang. Tapi Anda harus mengembalikan Property
jadi itu tidak mungkin.
Apakah saya benar-benar salah memahami cara melakukan pendekatan ini? Bagaimana seharusnya tes berbasis model kerja ditulis?