2016-10-26 4 views
1

ReadYamlValue과 비슷한 Play Json 유형과 비슷한 모나드 형 유형을 만들었습니다. 고양이와 함께 모나드를 테스트하는 법 +

trait ReadYamlValue[T] { 
    def read(json: YamlValue): ReadResult[T] 
    // ... methods include map, flatMap, etc 
} 

나는 이것에 대한 고양이 Monad 인스턴스를 생성 :

implicit val ReadYamlValueMonad: Monad[ReadYamlValue] = new Monad[ReadYamlValue] { 
    override def flatMap[A, B](fa: ReadYamlValue[A])(f: A => ReadYamlValue[B]): ReadYamlValue[B] = { 
    fa flatMap f 
    } 
    override def tailRecM[A, B](a: A)(f: A => ReadYamlValue[Either[A, B]]): ReadYamlValue[B] = { 
    ReadYamlValue.read[B] { yaml => 
     @tailrec def readB(reader: ReadYamlValue[Either[A, B]]): ReadResult[B] = { 
     reader.read(yaml) match { 
      case Good(Left(nextA)) => readB(f(nextA)) 
      case Good(Right(b)) => Good(b) 
      case Bad(error) => Bad(error) 
     } 
     } 
     readB(f(a)) 
    } 
    } 
    override def pure[A](x: A): ReadYamlValue[A] = ReadYamlValue.success(x) 
} 

을 그리고 나는 MonadLaws 및 ScalaCheck으로 테스트하고 싶었다.

class CatsTests extends FreeSpec with discipline.MonadTests[ReadYamlValue] { 
    monad[Int, Int, Int].all.check() 
} 

는하지만 얻을 :

could not find implicit value for parameter EqFA: cats.Eq[io.gloriousfuture.yaml.ReadYamlValue[Int]] 

가 어떻게 효과적으로 기능이 무엇인지에 대한 Eq을 정의합니까? 함수의 평등을 비교하는 것은 내가 원하는 것이 아닌 것처럼 보입니다 ... 내 ReadYamlValue 클래스가 모나드가 아니거나 Functor일까요? 이 작업을 수행하는

한 가지 방법은 임의의 샘플을 생성하고 결과의 평등을 비교하는 것입니다 :

implicit def eqReadYaml[T: Eq: FormatYamlValue: Arbitrary]: Eq[ReadYamlValue[T]] = { 
    Eq.instance { (a, b) => 
    val badYaml = arbitrary[YamlValue].getOrThrow 
    val goodValue = arbitrary[T].getOrThrow 
    val goodYaml = Yaml.write(goodValue) 
    Seq(badYaml, goodYaml).forall { yaml => 
     (a.read(yaml), b.read(yaml)) match { 
     case (Good(av), Good(bv)) => Eq.eqv(av, bv) 
     case (Bad(ae), Bad(be)) => Eq.eqv(ae, be) 
     case _ => false 
     } 
    } 
    } 
} 

을하지만 평등의 정의를 약간 피하는 것처럼이 보인다. 이 작업을 수행하는 데 더 나은 표준 방법이 있습니까? 그것은 임의의 인스턴스를 사용하여 모양

답변

1

는 키르케 그것을 수행하는 방법입니다

https://github.com/travisbrown/circe/blob/master/modules/testing/shared/src/main/scala/io/circe/testing/EqInstances.scala

그들은 16 개 샘플들의 스트림을하고 결과를 비교합니다.

+0

유일한 단점은 둘 모두 성공적으로 '읽혀질'단일 예제를 생성하지 않을 가능성이있는 것 같습니다. 16 개 모두 오류가 발생하고 성공 사례가 테스트되지 않을까 걱정됩니다. 이 문제는 'MonadLaws'테스트에 많은 영향을 줍니까? –

+0

디코딩 측면에서 circe는 임의의 'A'값을 생성 한 다음 인코딩해야합니다. 그런 다음 디코더가 동일한 작업을 수행하는지 확인해야합니다. –