Как расширить TestEnvironment теста ZIO

Я хочу протестировать следующую функцию:

def curl(host: String, attempt: Int = 200): ZIO[Loggings with Clock, Throwable, Unit]

Если бы среда просто использовала стандартные среды ZIO, например Console with Clock, тест будет работать из коробки:

testM("curl on valid URL") {
      (for {
        r <- composer.curl("https://google.com")
      } yield
        assert(r, isUnit))
    }

Среда тестирования будет предоставлена zio-test.

Итак, вопрос в том, как расширить TestEnvironment с помощью моего Loggings модуль?

2 ответа

Решение

Обратите внимание, что этот ответ относится к RC17 и значительно изменится в RC18. Вы правы в том, что, как и в других случаях создания сред, нам необходимо реализовать функцию для построения всей нашей среды из имеющихся у нас модулей. В Spec есть несколько встроенных комбинаторов, таких какprovideManagedдля этого вам не нужно делать это в самом тесте. Все они имеют "нормальные" варианты, которые будут предоставлять отдельную копию среды для каждого теста в наборе, и "общие" варианты, которые создадут одну копию среды для всего набора, когда это ресурс, создание которого требует больших затрат. как сервис Kafka.

Вы можете увидеть ниже пример использования provideSomeManaged чтобы предоставить среду, которая расширяет тестовую среду до теста.

В RC18 будет множество других вариантов обеспечения, эквивалентных тем, что есть в ZIO, а также новая концепция слоев, которая значительно упростит создание составных сред для приложений ZIO.

import zio._
import zio.clock._
import zio.test._
import zio.test.environment._

import ExampleSpecUtil._

object ExampleSpec
    extends DefaultRunnableSpec(
      suite("ExampleSpec")(
        testM("My Test") {
          for {
            time <- clock.nanoTime
            _ <- Logging.logLine(
              s"The TestClock says the current time is $time"
            )
          } yield assertCompletes
        }
      ).provideSomeManaged(testClockWithLogging)
    )

object ExampleSpecUtil {

  trait Logging {
    def logging: Logging.Service
  }

  object Logging {

    trait Service {
      def logLine(line: String): UIO[Unit]
    }

    object Live extends Logging {
      val logging: Logging.Service =
        new Logging.Service {
          def logLine(line: String): UIO[Unit] =
            UIO(println(line))
        }
    }

    def logLine(line: String): URIO[Logging, Unit] =
      URIO.accessM(_.logging.logLine(line))
  }

  val testClockWithLogging
      : ZManaged[TestEnvironment, Nothing, TestClock with Logging] =
    ZIO
      .access[TestEnvironment] { testEnvironment =>
        new TestClock with Logging {
          val clock = testEnvironment.clock
          val logging = Logging.Live.logging
          val scheduler = testEnvironment.scheduler
        }
      }
      .toManaged_
}

Вот что я придумал:

testM("curl on valid URL") {
      (for {
        r <- composer.curl("https://google.com")
      } yield
        assert(r, isUnit))
        .provideSome[TestEnvironment](env => new Loggings.ConsoleLogger
           with TestClock {
           override val clock: TestClock.Service[Any] = env.clock
           override val scheduler: TestClock.Service[Any] = env.scheduler
           override val console: TestLogger.Service[Any] = MyLogger()
      })
    }

Используя TestEnvironment с provideSome для настройки моей среды.

Другие вопросы по тегам