有没有一种规格匹配器可以拆开Option和Either?

8

我创建了一个规范测试,用于验证一些JSON解析。虽然测试效果非常好,但感觉有点冗长。

我想知道是否存在现有的规范代码来取消选项和Either?

"twitter json to Scala class mapper" should {
    "parsing a tweet" in {
      TwitterJsonMapper.tweetP(tweetS) match {
        case Right(t: Tweet) => {
          implicit def unOption[T](t: Option[T]): T = t.get
          implicit def unEither[T](t: Either[T,Throwable]): T = t match {case Left(left) => left ;case Right(t) => throw t}
          "test id" in {
            true must_== (t.id.get == 228106060337135617l)
          }
          "test id_str" in {
            true must_== (t.id_str.get == "228106060337135617")
          }
          "test time" in {
            true must_== (t.created_at.getHours == 13 )
          }
        }
        case Left((pe: JsonParseException, reason: String)) => fail(reason + "\n" + pe)
      }
    }
  }

 //The Tweet is produced from JSON using Fasterxml's Jackson-Scala library. 
 //I want to use Option or Either monads over all child attributes - for the usual reasons.
case class Tweet(
  @BeanProperty contributors: Option[String],
  @BeanProperty coordinates: Option[String],

  @BeanProperty @JsonDeserialize (
      using = classOf[TwitterDateDeserializer]
  ) created_at: Either[Date,Throwable],
  @BeanProperty favorited: Boolean = false,
  //elided etc etc
  @BeanProperty id_str: Option[String]
}

1
是的,请参阅匹配器指南:http://etorreborre.github.com/specs2/guide/org.specs2.guide.Matchers.html#Matchers - Ben Manes
啊,好的。我忘了说,我还在使用Specs 1版本。我只有很少的时间来升级我的库。这个功能不在Specs 1中吗? - Bryan Hunt
要建立一个可靠的Scala / Maven / Eclipse / Specs - 工具链真的很难。我设法让Specs与Eclipse配合运作,并固定了我的依赖的那部分配置。 - Bryan Hunt
您在升级过程中遇到了任何问题吗? - Bryan Hunt
我从specs2开始,所以无法评论迁移。由于社区变化的速度,我会虔诚地升级我的Scala项目。我发现Gradle优于SBT / Maven,因为我已广泛使用过它们三个。有关specs1匹配器,请参阅http://code.google.com/p/specs/wiki/MatchersGuide。 - Ben Manes
显示剩余2条评论
2个回答

7

确实有一些针对 OptionEither 的特殊匹配器:

t.id must beSome(228106060337135617l)
t.id_str must beSome("228106060337135617")
t.created_at.left.map(_.getHours) must beLeft(13)

顺便提一下,当你想测试一个布尔值时,你可以写成(t.id.get == 228106060337135617l) must beTrue,而不是写成true must_== (t.id.get == 228106060337135617l) - Eric
是的,这更具审美感。 - Bryan Hunt
这些匹配器不是类型安全的。Left(24) must beLeft("FUBAR")Some(42) must beSome("FUBAR")都可以编译通过,但只有在运行时才会失败。从长远来看,多写几个单词值得你浪费的时间去弄清楚为什么测试失败了。 - drstevens
啊哦,有点儿沮丧!不过没关系,这只是为了进行一次健全性检查,把它放出来看看社区的反应还是很有价值的。 - Bryan Hunt

2

我认为这并不必要。记住,Option/Either具有值相等性。只需匹配Option/Either而不是它们包含的值。

      "Option should match other options" >> {
        Some(21) must be equalTo Some(21)
      }

      "Either should match Either" >> {
        Right("Some string") must be equalTo Right("Some string")
      }

我尝试没有编译这些代码,但是它们应该可以正常运行。你可能需要添加一些明确的类型(或使用不安全的must_==)。
      t.id must be equalTo Some(228106060337135617l)
      t.id_str must be equalTo Some("228106060337135617")
      t.created_at.left.map(_.getHours) must be equalTo Left(13)

试图减少混乱,需要验证34个属性。 - Bryan Hunt
通常情况下,我不会对我试图验证的每个属性进行包装。我之所以这样做,只是因为它在你的示例中。我已经更新了代码,删除了多余的规范。 - drstevens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接