Here is the code being tested:
import concurrent.{ExecutionContext, Future}
trait Backend {
def verifyUser(): Future[Unit]
def accounts(): Future[String]
}
class Service(backend: Backend) {
private implicit val executor: ExecutionContext = ExecutionContext.global
def accounts(): Future[String] =
(for (_ <- backend.verifyUser(); accs <- backend.accounts()) yield accs)
.recover { case ex => s"failed: ${ex.getMessage}" }
}
and the test
import org.scalatest._
import matchers.should
import flatspec.AsyncFlatSpec
import org.mockito.scalatest.AsyncIdiomaticMockito
class ServiceTest extends AsyncFlatSpec with AsyncIdiomaticMockito with should.Matchers {
private trait Fixture {
lazy val backend: Backend = mock[Backend]
lazy val service: Service = new Service(backend)
}
it should "return the reason of a failure" in {
val fixture = new Fixture {}
import fixture._
backend.verifyUser() returns Future.failed(new RuntimeException("verifyUser"))
backend.accounts() returns Future.failed(new RuntimeException("accounts"))
service.accounts() map { result =>
result should startWith ("failed: ")
}
}
}
The result is
Unnecessary stubbings detected.
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
1. -> at ServiceTest.$anonfun$new$1(StrictStubbingTest.scala:25)
Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class.
org.mockito.exceptions.misusing.UnnecessaryStubbingException:
How can I make the test working leaving both stubs? How can I enable 'lenient' strictness as suggested just for that very test case, not for the whole test class?
My teammate gave such a solution:
class ServiceTest extends AsyncFlatSpec with AsyncIdiomaticMockito with should.Matchers {
private trait Fixture {
lazy val backend: Backend = mock[Backend]
lazy val service: Service = new Service(backend)
}
it should "return the reason of a failure" in {
val fixture = new Fixture {
override lazy val backend: Backend = mock[Backend](withSettings.lenient())
}
import fixture._
backend.verifyUser() returns Future.failed(new RuntimeException("verifyUser"))
backend.accounts() returns Future.failed(new RuntimeException("accounts"))
service.accounts() map { result =>
result should startWith ("failed: ")
}
}
}
that is to make a lenient mock of Backend
.