9

I am relatively new to Scala Test, and so I consulted the documentation on how to test on Either values.

I tried to replicate the instructions like that:

import org.scalatest.EitherValues
import org.scalatest.flatspec.AnyFlatSpec

class EitherTest extends AnyFlatSpec with EitherValues {
  val either: Either[Exception, Int] = Right(42)

  either.right.value should be > 1
}

This implementation does not do the trick, I get a syntax error. What did I do wrong?

Error:

Error:(9, 22) value should is not a member of Int either.right.value should be > 1 Error:(9, 29) not found: value be either.right.value should be > 1 – Hannes 14 hours ago

pedrorijo91
  • 7,635
  • 9
  • 44
  • 82
Hannes
  • 5,002
  • 8
  • 31
  • 60
  • 1
    what is the error you get? can you add that as well please – sinanspd Dec 21 '19 at 22:52
  • `Error:(9, 22) value should is not a member of Int either.right.value should be > 1 Error:(9, 29) not found: value be either.right.value should be > 1` – Hannes Dec 21 '19 at 22:59
  • Can you try removing the explicit type signature from Either and see if that works? ```val either = Right(42) ``` – sinanspd Dec 21 '19 at 23:02
  • 5
    @Hannes: I think you're missing the mix-in `Matchers` (eg `class EitherTest extends AnyFlatSpec with EitherValues with Matchers`). – Marth Dec 21 '19 at 23:03
  • @Marth mixing-in `org.scalatest.matchers.should.Matchers` got rid of the syntax error but my IDE still states that `Either.right` is deprecated since Scala 2.13.0, Is that expected? – Hannes Dec 21 '19 at 23:10
  • Yes Either.right is deprecated as it is right oriented. either.contains or either.exists should work for you. – Salim Dec 22 '19 at 02:22
  • A workaround I found is using `with OptionValues` instead and then `either.toOption.value`. – BennyMcBenBen May 14 '21 at 01:56

4 Answers4

6

Testing Either by matching with pattern can be more readable. ScalaTest's Inside trait allows you to make assertions after a pattern match.

import org.scalatest.Inside
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class EitherTest extends AnyFlatSpec with Inside with Matchers {
  val either: Either[Exception, Int] = Right(42)

  either should matchPattern { case Right(42) => }

  inside(either) { case Right(n) =>
    n should be > 1
  }

  val either2: Either[Exception, Int] = Left(new Exception("Bad argument"))

  inside(either2) { case Left(e) =>
    e.getMessage should startWith ("Bad")
  }

}
Yuriy Tumakha
  • 1,450
  • 17
  • 21
  • Thank you for this code snippet, I will give it a try! But I've got two questions: 1) What is that `=> }` syntax? I know the match syntax but I did not know that you can leave out the right part of the expression. 2) Can `matchPattern` be used together with the `"Either" should matchPattern in { ...}` syntax? – Hannes Dec 22 '19 at 19:28
  • @Hannes 1. right part is empty Unit without any implementation. We have only checking either matched with the pattern. 2. More details about matching a pattern in Scalatest docs http://www.scalatest.org/user_guide/using_matchers#matchingAPattern – Yuriy Tumakha Dec 24 '19 at 17:07
5

There is an open pull request Add EitherValuable #1712 which aims to address the fact that in Scala 2.13 the RightProjection is deprecated:

at present .right is deprecated (and I believe it will stay that way) but .left isn't, as per scala/scala#8012

The new syntax of EitherValues in future ScalaTest versions might become rightValue and leftValue like so

either.rightValue should be > 1
Mario Galic
  • 47,285
  • 6
  • 56
  • 98
4

Here is how I would do it.

Check first if it is right and then compare the value:

either.isRight shouldBe true
either.getOrElse(0) shouldBe 42

Another way is to fail in case it is not right:

either.getOrElse(fail("either was not Right!")) shouldBe 42

I also would wrap your test, for example as WordSpec:

"My Either" should {
  "be Right" in {
    either.getOrElse(fail("either was not Right!")) shouldBe 42
  }
}

This hints you where the problem is. Otherwise, if it fails, all you get is a nasty error stack.

And here the whole example:

class EitherTest
  extends WordSpec
  with Matchers
  with EitherValues {

  // val either: Either[Exception, Int] = Right(42)
  val either: Either[Exception, Int] = Left(new IllegalArgumentException)
  "My Either" should {
    "be Right" in {
      either.getOrElse(fail("either was not Right!")) shouldBe 42
    }
  }
}
pme
  • 14,156
  • 3
  • 52
  • 95
0

Did you consider the inside trait? That way you can test for the value inside your Either using pattern matching. For example:

import org.scalatest.Inside.inside
...
val result = FooBarInputValidator(value)
inside(result) { case Left(validationError) => 
   validationError.message shouldBe "Invalid input"
   validationError.parameter shouldBe "FooBar"
}
Pepster
  • 1,996
  • 1
  • 24
  • 41