无法获得基于模型的测试工作
Cannot get model based test working
作为练习,我想实现一个 2-3 指树。那应该是尝试 FsCheck's model-based testing. I decided to try the newer experimental version.
的绝佳机会
到目前为止,我只为测试机编写了一个命令,因为我已经无法使它工作——另一方面它使 post 保持简短。完整代码可在 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"
我的理解是这样的:Operation<_>.Run
是 运行 两次,从一个元素构建一个 ResizeArray
。然后 Operation<_>.Check
是 运行 两次相同的数字插入到单个元素 FingerTree<_>
.
两次传球中的第一次。单元素树传入,添加使其成为(正确的)二元素树,与第一个命令后的模型相比效果很好。
第二个命令总是失败的。 Check
使用更大的 ResizeList
(现在有 3 个元素)调用,但与第一个命令中的单元素树相同。当然,再添加一个元素不会使其达到大小 3,测试失败。
我原以为我需要 return 来自 Check
的更新模型才能收到命令。但是你需要return一个Property
所以这是不可能的。
我是不是完全误解了如何处理这个问题?应该如何编写基于工作模型的测试?
基于模型的测试假定 "system under test" 在特定操作上调用 Check
时被修改为副作用,并在 运行 时为该测试初始化 运行 =12=] 被调用。它旨在处理可变的系统 - 就像一个可变的对象 - 这种风格虽然在这里有点令人困惑,但对于这样的系统来说效果很好。
由于您的手指树类型是不可变的,我的建议是将 SutType
重新定义为:
type SutType = Ref<FingerTree<TestType>>
并相应地修改其余部分。
作为练习,我想实现一个 2-3 指树。那应该是尝试 FsCheck's model-based testing. I decided to try the newer experimental version.
的绝佳机会到目前为止,我只为测试机编写了一个命令,因为我已经无法使它工作——另一方面它使 post 保持简短。完整代码可在 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"
我的理解是这样的:Operation<_>.Run
是 运行 两次,从一个元素构建一个 ResizeArray
。然后 Operation<_>.Check
是 运行 两次相同的数字插入到单个元素 FingerTree<_>
.
两次传球中的第一次。单元素树传入,添加使其成为(正确的)二元素树,与第一个命令后的模型相比效果很好。
第二个命令总是失败的。 Check
使用更大的 ResizeList
(现在有 3 个元素)调用,但与第一个命令中的单元素树相同。当然,再添加一个元素不会使其达到大小 3,测试失败。
我原以为我需要 return 来自 Check
的更新模型才能收到命令。但是你需要return一个Property
所以这是不可能的。
我是不是完全误解了如何处理这个问题?应该如何编写基于工作模型的测试?
基于模型的测试假定 "system under test" 在特定操作上调用 Check
时被修改为副作用,并在 运行 时为该测试初始化 运行 =12=] 被调用。它旨在处理可变的系统 - 就像一个可变的对象 - 这种风格虽然在这里有点令人困惑,但对于这样的系统来说效果很好。
由于您的手指树类型是不可变的,我的建议是将 SutType
重新定义为:
type SutType = Ref<FingerTree<TestType>>
并相应地修改其余部分。