我试图找出为支持两个端点的 Http4s 应用程序编写集成测试的习惯用法。我通过在新光纤上分叉它来启动Main
应用程序类,然后在发布. 然后我将其转换为 a并通过具有多个s的整体传递它。ZManaged
ZManaged
ZLayer
provideCustomLayerShared()
suite
testM
- 我在正确的轨道上吗?
- 它的行为不像我预期的那样:
- 尽管以上述方式管理的 httpserver 已提供给包含两个测试的套件,但它在第一次测试后被释放,因此第二次测试失败
- 测试套件永远不会完成,只是在执行两个测试后挂起
为下面的代码半生不熟的性质道歉。
object MainTest extends DefaultRunnableSpec {
def httpServer =
ZManaged
.make(Main.run(List()).fork)(fiber => {
//fiber.join or Fiber.interrupt will not work here, hangs the test
fiber.interruptFork.map(
ex => println(s"stopped with exitCode: $ex")
)
})
.toLayer
val clockDuration = 1.second
//did the httpserver start listening on 8080?
private def isLocalPortInUse(port: Int): ZIO[Clock, Throwable, Unit] = {
IO.effect(new Socket("0.0.0.0", port).close()).retry(Schedule.exponential(clockDuration) && Schedule.recurs(10))
}
override def spec: ZSpec[Environment, Failure] =
suite("MainTest")(
testM("Health check") {
for {
_ <- TestClock.adjust(clockDuration).fork
_ <- isLocalPortInUse(8080)
client <- Task(JavaNetClientBuilder[Task](blocker).create)
response <- client.expect[HealthReplyDTO]("http://localhost:8080/health")
expected = HealthReplyDTO("OK")
} yield assert(response) {
equalTo(expected)
}
},
testM("Distances endpoint check") {
for {
_ <- TestClock.adjust(clockDuration).fork
_ <- isLocalPortInUse(8080)
client <- Task(JavaNetClientBuilder[Task](blocker).create)
response <- client.expect[DistanceReplyDTO](
Request[Task](method = Method.GET, uri = uri"http://localhost:8080/distances")
.withEntity(DistanceRequestDTO(List("JFK", "LHR")))
)
expected = DistanceReplyDTO(5000)
} yield assert(response) {
equalTo(expected)
}
}
).provideCustomLayerShared(httpServer)
}
测试的输出是第二个测试失败,而第一个测试成功。我进行了足够多的调试,发现 HTTPServer 在第二次测试之前已经关闭。
stopped with exitCode: ()
- MainTest
+ Health check
- Distances endpoint check
Fiber failed.
A checked error was not handled.
org.http4s.client.UnexpectedStatus: unexpected HTTP status: 404 Not Found
并且无论我是否在 sbt testOnly 上运行 Intellij 的测试,测试过程都会在这一切之后一直挂起,我必须手动终止它。