8

I've created a specs test, to validate some JSON parsing. Although the test works perfecly well, it feels rather noisy.

I wonder if there is existing code in Specifications to unbox Option and 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]
}
Bryan Hunt
  • 3,685
  • 2
  • 24
  • 36
  • 1
    Yes, see the matchers guide: http://etorreborre.github.com/specs2/guide/org.specs2.guide.Matchers.html#Matchers – Ben Manes Jul 29 '12 at 12:37
  • Ah, ok. I forgot to say, I'm still on Specs 1. Only got so much time to spend on upgrading my libraries. Is the feature not in Specs 1? – Bryan Hunt Jul 29 '12 at 14:36
  • It's just so difficult to get a reliable scala / maven / eclipse / specs - toolchain - up and running. I got specs to work with Eclipse and froze that section of my dependencies. – Bryan Hunt Jul 29 '12 at 14:38
  • Have you encountered any problems while upgrading? – Bryan Hunt Jul 29 '12 at 14:40
  • I started on specs2, so I can't comment on migration. I upgrade my Scala projects religiously due to the pace of change in the community. I found Gradle to be superior to SBT/Maven, having used all extensively. For specs1 matchers see http://code.google.com/p/specs/wiki/MatchersGuide – Ben Manes Jul 29 '12 at 23:03
  • Hmm, gradle doesn't integrate with Scala-IDE... that could be a recipe for some serious yak shaving ;) – Bryan Hunt Jul 30 '12 at 09:18
  • the gradle sts plugin + scala-ide work fine for me. http://static.springsource.org/sts/docs/latest/reference/html/gradle/ – Ben Manes Jul 31 '12 at 01:34

2 Answers2

7

There are indeed some specific matchers for Option and Either:

t.id must beSome(228106060337135617l)
t.id_str must beSome("228106060337135617")
t.created_at.left.map(_.getHours) must beLeft(13)
Eric
  • 15,494
  • 38
  • 61
  • By the way, instead of writing `true must_== (t.id.get == 228106060337135617l)` you can write `(t.id.get == 228106060337135617l) must beTrue` when you want to test a Boolean value. – Eric Jul 29 '12 at 23:27
  • Yes, that is more aesthetically pleasing – Bryan Hunt Jul 30 '12 at 09:21
  • These matchers are not type safe. `Left(24) must beLeft("FUBAR")` and `Some(42) must beSome("FUBAR")` both compile. They only fail at runtime. In the long run, the extra couple of words will be worth the time you wasted trying to figure out why your test is failing. – drstevens Jul 30 '12 at 15:06
  • Aww. Downer!Oh well, it was really just for a sanity check, worth putting it out there and seeing what the community made of it. – Bryan Hunt Jul 31 '12 at 13:50
2

I haven't found this necessary. Remeber, Option/Either have value equality. Just match the Option/Either instead of matching the values they contain.

      "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")
      }

I didn't try to compile these, but they should work. You may need to add some explicit typing (or use must_== which isn't type safe)

      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)
drstevens
  • 2,903
  • 1
  • 21
  • 30
  • Trying to cut down on clutter, have 34 attributes to validate – Bryan Hunt Jul 30 '12 at 09:19
  • Well, normally I wouldn't have wrapped each attribute I was trying to validate. I only did that because it was in your example. I updated to remove the extra specs clutter. – drstevens Jul 30 '12 at 14:24