2016-10-11 15 views
1

연습으로 2-3 손가락 트리를 구현하고 싶습니다. 그것은 FsCheck의 모델 기반 테스팅을 시험해 볼 수있는 완벽한 기회 여야합니다. 나는 더 새로운 것을 시도하기로 결정했다 experimental version.모델 기반 테스트 작동을 얻을 수 없습니다.

지금까지 나는 테스트 머신에 대해 하나의 명령만을 코딩했습니다. 왜냐하면 나는 이미 그 작업을하는데 실패했기 때문입니다. 전체 코드는 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<_>에 삽입합니다.

두 패스 중 첫 번째 패스입니다. 단일 요소 트리가 들어오고 추가되면 첫 번째 명령 이후에 모델과 잘 비교되는 (올바른) 2- 요소 트리가됩니다.

두 번째 명령은 항상 실패한 명령입니다. Check은 더 큰 ResizeList (현재 3 개 요소)이지만 첫 번째 명령과 동일한 단일 요소 트리를 사용하여 호출됩니다. 물론 요소를 하나 더 추가해도 크기가 3이되지 않으므로 테스트가 실패합니다.

커맨드를 위해 Check에서 업데이트 된 모델을 반환해야한다고 예상 했었습니다. 그러나 Property을 반환해야합니다. 그렇게 할 수는 없습니다.

이 접근 방법에 대해 완전히 오해 했습니까? 모델 기반 테스트는 어떻게 작성되어야합니까?

답변

2

모델 기반 테스트에서는 특정 작업에서 Check이 호출 될 때 "테스트중인 시스템"이 부작용으로 수정되고 Setup.Actual()이 호출 될 때 해당 테스트 실행을 위해 초기화된다고 가정합니다. 그것은 가변적 인 객체처럼 가변적 인 시스템을 다루기 위해 고안되었습니다. 그리고 그 스타일은 다소 어리둥절하게 만들지 만 그러한 시스템에서는 꽤 잘 작동합니다.

type SutType = Ref<FingerTree<TestType>> 

하고 그에 따라 나머지 부분을 수정 : 손가락 트리 유형이 불변이므로

, 내 조언에 SutType을 재정의하는 것입니다.

+0

잘 알고 있습니다. 그것이 어딘가에서 문서에 언급되어 있습니까? 어쩌면 더 두드러 질 것입니다. 감사. – primfaktor

+0

분명히 눈에 띄지 않으면 눈에 띄지 않습니다. :) –