scalatest - протестировать метод Future[S] с помощью fallbackTo

Предпосылка: Когда мой API отвечает на запрос объекта User, я хочу попробовать обогатить его свойствами case class PartnerView(id: String, vipStatus: Option[Boolean], latestSession: Option[Timestamp]. Поскольку база данных иногда может быть ненадежной, я использую fallbackTo для предоставления значений как необязательных, поэтому они не отображаются в ответе пользователя JSON.

Следующая реализация, похоже, работает до сих пор (запуск запроса через Postman возвращает пользовательский JSON без необязательных значений), но мой модульный тест будет жаловаться, как если бы у меня было необработанное исключение.

Класс обслуживания:

class Service(repo: Repository) {
  def get(id: String): Future[Partner] = {
    val account = repo.getAccount(id)
    val getLatestSession = repo.getLatestSession(id)

    val partnerView = (for {
      account <- getAccount
      latestStartTime <- getLatestSession.map {
        case Some(x) => x.scheduledStartTime
        case _ => None
      }
    } yield PartnerView(partnerId, account.vipStatus, latestStartTime))
      .fallbackTo(Future.successful(PartnerView(id, None, None)))

    partnerView
  }
}

Класс репозитория:

class Repository(database: DatabaseDef, logger: LoggingAdapter) {
  def getAccount(id: String): Future[Account] = database.run((...).result.head)
    .recover {
      case e: Exception =>
        logger.error(e, "DB Server went down")
        throw e
    }

  def getLatestSession(id: String): Future[Option[Session]] = database.run((...).result.headOption)
    .recover {
      case e: Exception =>
        logger.error(e, "DB Server went down")
        throw e
    }
}

Модульный тест:

class ServiceSpec extends AsyncFlatSpec with AsyncMockFactory with OneInstancePerTest {
  val mockRepo = mock[Repository]
  val service = new Service(mockRepo)

  behaviour of "Service"

  it should "get an empty PartnerView when the repository get an Exception" in {
    (mockRepository.getAccount _)
      .expects("partner")
      .throwing(new Exception)

    service.get("partner")
      .map(partnerView => assert(partnerView.id == "partner" && partnerView.vipStatus.isEmpty))
  }
}

Тест завершится ошибкой с сообщением

Testing started at 5:15 p.m. ...









java.lang.Exception was thrown.
{stacktrace here}

Я ожидаю, что Exception


person Thanh-Châu Phạm    schedule 23.04.2021    source источник
comment
.getAccount не должно быть throwing в вашей настройке. Он должен вернуть Future.failed(new Excpeption)).   -  person Dima    schedule 23.04.2021
comment
@Дима, вот оно!   -  person Thanh-Châu Phạm    schedule 24.04.2021


Ответы (1)


Изменив настройку макета на приведенную ниже, тест прошел успешно:

  it should "get an empty PartnerView when the repository get an Exception" in {
    (mockRepository.getAccount _)
      .expects("partner")
      .returning(Future.failed(new Exception))

    ...
  }

так как метод recover заключает Exception в Future

Источники:

восстановление против восстановления с помощью

официальная статья о scala

person Thanh-Châu Phạm    schedule 25.04.2021