'A test is using time, but is not advancing the test clock' 在 ZIO 测试中
'A test is using time, but is not advancing the test clock' in ZIO Test
将我的测试迁移到 RC18 后,我收到以下警告并且测试挂起:
Warning: A test is using time, but is not advancing the test clock, which may result in the test hanging. Use TestClock.adjust to manually advance the time.
我有以下测试:
val testLayer: ZLayer[Live, Nothing, Loggings with Blocking with Clock] = (Console.live >>> loggings.consoleLogger) ++ Blocking.live ++ TestClock.default
testM("curl on invalid URL") {
for {
fork <- composer.curl("https://bad.xx", 1).flip.fork
_ <- TestClock.adjust(3.second * 2)
r <- fork.join
} yield
assert(r)(isSubtype[DockerComposerException](hasField("msg", _.msg.trim, equalTo("https://bad.xx could not be reached!"))))
}.provideCustomLayer(testLayer)
我怀疑我创建的层有误,因为这是我为迁移所做的唯一更改。
文档中的标准测试也失败了(时间为 0):
testM("One can move time very fast") {
for {
startTime <- currentTime(TimeUnit.SECONDS)
_ <- TestClock.adjust(Duration.fromScala(1 minute))
endTime <- currentTime(TimeUnit.SECONDS)
} yield assert(endTime - startTime)(isGreaterThanEqualTo(60L))
}
当我像这样定义图层时:
val testLayer: ZLayer[Live, Nothing, Loggings with Blocking with Clock] = (Console.live >>> loggings.consoleLogger) ++ Blocking.live ++ Clock.live
时间完全没有调整
这是我要测试的代码:
def curl(host: String, attempt: Int = 200): ZIO[Loggings with Clock, Throwable, Unit] = {
ZIO.effect(
Process(Seq("curl", "--output", "/dev/null", "--silent", "--head", "--fail", host)).!!
).flatMap(r =>
info(s"\n$host is ready to use") *> ZIO.succeed()
).catchAll(t =>
if (attempt == 0)
ZIO.fail(DockerComposerException(s"\n$host could not be reached!", Some(t)))
else
info(s"still waiting ;(") *>
ZIO.sleep(3.second) *>
curl(host, attempt - 1)
)
}
所以我想快进ZIO.sleep(3.seconds)
。
您需要在 adjust(duration)
之后调用 sleep(duration)
,以便在调用 currentTime
时反映调整后的时间。所以上面例子的正确版本是:
testM("One can move time very fast") {
for {
startTime <- currentTime(TimeUnit.SECONDS)
_ <- TestClock.adjust(1.minute)
_ <- ZIO.sleep(1.minute)
endTime <- currentTime(TimeUnit.SECONDS)
} yield assert(endTime - startTime)(isGreaterThanEqualTo(60L))
}
请注意,这反映在当前版本的文档中 here 但尚未反映在网站上,因为我们目前仅在发布时发布更改。
不过,我认为这不是你的问题,因为看起来你的效果只是在使用睡眠。
我无法完全重现您的代码,但以下稍微简化的示例可以正常工作:
import zio._
import zio.clock.Clock
import zio.console.Console
import zio.duration._
import zio.test._
import zio.test.environment.TestClock
object ExampleSpec extends DefaultRunnableSpec {
type Logging = Has[Logging.Service]
object Logging {
trait Service {
def logLine(line: String): UIO[Unit]
}
val live: ZLayer[Console, Nothing, Logging] =
ZLayer.fromService { console =>
new Logging.Service {
def logLine(line: String): UIO[Unit] =
console.putStrLn(line)
}
}
def logLine(line: String): ZIO[Logging, Nothing, Unit] =
ZIO.accessM(_.get.logLine(line))
}
def effect(n: Int): ZIO[Clock with Logging, String, Unit] =
if (n == 0) ZIO.fail("fail")
else Logging.logLine("retrying") *> ZIO.sleep(3.seconds) *> effect(n -1)
def spec = suite("ExampleSpec") {
testM("test") {
for {
fiber <- effect(1).flip.fork
_ <- TestClock.adjust(6.seconds)
_ <- fiber.join
} yield assertCompletes
}.provideCustomLayer(Logging.live)
}
}
您的测试中是否还有其他问题?
将我的测试迁移到 RC18 后,我收到以下警告并且测试挂起:
Warning: A test is using time, but is not advancing the test clock, which may result in the test hanging. Use TestClock.adjust to manually advance the time.
我有以下测试:
val testLayer: ZLayer[Live, Nothing, Loggings with Blocking with Clock] = (Console.live >>> loggings.consoleLogger) ++ Blocking.live ++ TestClock.default
testM("curl on invalid URL") {
for {
fork <- composer.curl("https://bad.xx", 1).flip.fork
_ <- TestClock.adjust(3.second * 2)
r <- fork.join
} yield
assert(r)(isSubtype[DockerComposerException](hasField("msg", _.msg.trim, equalTo("https://bad.xx could not be reached!"))))
}.provideCustomLayer(testLayer)
我怀疑我创建的层有误,因为这是我为迁移所做的唯一更改。
文档中的标准测试也失败了(时间为 0):
testM("One can move time very fast") {
for {
startTime <- currentTime(TimeUnit.SECONDS)
_ <- TestClock.adjust(Duration.fromScala(1 minute))
endTime <- currentTime(TimeUnit.SECONDS)
} yield assert(endTime - startTime)(isGreaterThanEqualTo(60L))
}
当我像这样定义图层时:
val testLayer: ZLayer[Live, Nothing, Loggings with Blocking with Clock] = (Console.live >>> loggings.consoleLogger) ++ Blocking.live ++ Clock.live
时间完全没有调整
这是我要测试的代码:
def curl(host: String, attempt: Int = 200): ZIO[Loggings with Clock, Throwable, Unit] = {
ZIO.effect(
Process(Seq("curl", "--output", "/dev/null", "--silent", "--head", "--fail", host)).!!
).flatMap(r =>
info(s"\n$host is ready to use") *> ZIO.succeed()
).catchAll(t =>
if (attempt == 0)
ZIO.fail(DockerComposerException(s"\n$host could not be reached!", Some(t)))
else
info(s"still waiting ;(") *>
ZIO.sleep(3.second) *>
curl(host, attempt - 1)
)
}
所以我想快进ZIO.sleep(3.seconds)
。
您需要在 adjust(duration)
之后调用 sleep(duration)
,以便在调用 currentTime
时反映调整后的时间。所以上面例子的正确版本是:
testM("One can move time very fast") {
for {
startTime <- currentTime(TimeUnit.SECONDS)
_ <- TestClock.adjust(1.minute)
_ <- ZIO.sleep(1.minute)
endTime <- currentTime(TimeUnit.SECONDS)
} yield assert(endTime - startTime)(isGreaterThanEqualTo(60L))
}
请注意,这反映在当前版本的文档中 here 但尚未反映在网站上,因为我们目前仅在发布时发布更改。
不过,我认为这不是你的问题,因为看起来你的效果只是在使用睡眠。
我无法完全重现您的代码,但以下稍微简化的示例可以正常工作:
import zio._
import zio.clock.Clock
import zio.console.Console
import zio.duration._
import zio.test._
import zio.test.environment.TestClock
object ExampleSpec extends DefaultRunnableSpec {
type Logging = Has[Logging.Service]
object Logging {
trait Service {
def logLine(line: String): UIO[Unit]
}
val live: ZLayer[Console, Nothing, Logging] =
ZLayer.fromService { console =>
new Logging.Service {
def logLine(line: String): UIO[Unit] =
console.putStrLn(line)
}
}
def logLine(line: String): ZIO[Logging, Nothing, Unit] =
ZIO.accessM(_.get.logLine(line))
}
def effect(n: Int): ZIO[Clock with Logging, String, Unit] =
if (n == 0) ZIO.fail("fail")
else Logging.logLine("retrying") *> ZIO.sleep(3.seconds) *> effect(n -1)
def spec = suite("ExampleSpec") {
testM("test") {
for {
fiber <- effect(1).flip.fork
_ <- TestClock.adjust(6.seconds)
_ <- fiber.join
} yield assertCompletes
}.provideCustomLayer(Logging.live)
}
}
您的测试中是否还有其他问题?