Какой тип использовать в тестах, для которых требуется экземпляр класса Concurrent и Timer? - PullRequest
0 голосов
/ 24 января 2019

Рассмотрим следующий пример:

import cats.Functor
import cats.effect.{Concurrent, Timer}
import cats.syntax.functor._
import fs2.Stream

import scala.concurrent.duration._

class FetchAndSum[F[_]: Timer: Concurrent: Functor](fetch: List[String] => F[List[Int]]) {

  def run(inputs: List[String]): F[Int] =
    Stream
      .emits(inputs)
      .covary[F]
      .groupWithin(20, 10.millis)
      .mapAsync(10)(chunk => fetch(chunk.toList))
      .flatMap(Stream.emits)
      .reduce(_ + _)
      .compile
      .last
      .map(_.getOrElse(0))
}

В производстве это создается с помощью IO Монады.

В моих тестах я хотел бы проверить сколько разfetch функция вызывается .Если для F[_] потребуется только экземпляр Functor, я мог бы сделать это просто с помощью монады Writer.

Из-за mapAsync и groupedWithin из fs2, F[_] также должен иметьэкземпляры Timer и Concurrent, которые, конечно, не существуют на Writer.

Какой тип данных я мог бы использовать для функциональной проверки этого?

Я думал окаким-то образом комбинируя IO с Writer, например type IOWriter[A] = IO[Writer[Int, A]], но я не смог заставить это работать без повторного выделения всех экземпляров класса типов для IOWriter.

Есть ли что-то, что позволяет мнедостичь этого без необходимости переопределять все экземпляры классов типов?

1 Ответ

0 голосов
/ 24 января 2019

Используйте IO с Ref:

val numsExecuted: IO[Int] = for {
  ref <- Ref[IO].of(0)
  fetch = (l: List[String]) => ref.update(_ + 1).as(???)
  _ <- new FetchAndSum[IO](fetch).run(???)
  x <- ref.get
} yield x

Вы также можете использовать Writer в сочетании с IO.Эта конструкция известна как монадный преобразователь Writer (type IOWriter[A] = cats.data.WriterT[IO, A]) и должна иметь экземпляры Concurrent / Timer / Monad / etc. из коробки.

...