在 Javalin 处理程序中调用时,Junit 断言不起作用
Junit assertions don't work when called inside a Javalin handler
我有这个测试在端口 7000
启动服务,在唯一的端点内我做了一个失败的断言:
@Test
fun `javalin assertion should fail`() {
Javalin.create()
.get("/") { assertTrue(false) }
.start()
newHttpClient().send(
HttpRequest.newBuilder()
.uri(URI.create("http://localhost:7000/"))
.GET().build(),
discarding()
)
}
问题是测试总是通过(但应该会失败):
(运行ning ./gradlew test
发生同样的行为)
...即使控制台输出声称测试失败:
[Test worker] INFO io.javalin.Javalin - Listening on http://localhost:7000/
[Test worker] INFO io.javalin.Javalin - Javalin started in 356ms \o/
[qtp2100106358-22] ERROR io.javalin.Javalin - Exception occurred while servicing http-request
org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
..
可能 运行 在另一个线程中,但我想知道是否有办法将它附加到相同的上下文中。
(奇怪的是,在我的应用程序的另一个场景中——我无法隔离——它正常地失败了。)
TLDR
要使测试如您预期的那样失败,请在您从 Javalin 实例获得的响应上添加一个断言。
@Test
fun `javalin assertion should fail`() {
Javalin.create()
.get("/") { assertTrue(false) } // or any expression that throws an Exception, like Kotlin's TODO()
.start()
val javalinResponse: HttpResponse<Void> = newHttpClient().send(
HttpRequest.newBuilder()
.uri(URI.create("http://localhost:7000/"))
.GET().build(),
discarding()
)
assertThat(javalinResponse.statusCode()).isEqualTo(200) // will fail with Expected: 200, Actual: 500
}
详情
测试中有两个不同的步骤:新的 Javalin 实例配置 + 构建,以及使用 HttpClient 调用该实例。
在 Javalin 配置 + 构建步骤中,它被指示在 /
端点上调用时执行 assertTrue(false)
。 assertTrue(false)
将抛出一个 AssertionFailedError
,但如果你在那里抛出其他东西,行为将是相同的。现在,与许多(所有?)其他网络服务器一样,Javalin / Jetty 将尝试捕获其中发生的任何未捕获的异常和 return 代码为 500(内部服务器错误)的 HTTP 响应。
事实上,这一切都发生在另一个线程中,因为在内部启动了一个 Jetty 网络服务器实例,它执行端口侦听、HTTP 请求/响应处理和其他重要的事情。
因此,当稍后在测试中对新的 Javalin 实例执行 HTTP 调用时,它会成功获得 500(内部服务器错误)响应,并且最初没有对响应的断言并且没有未捕获的异常,测试成功。
永远不要在 Javalin 处理程序内部进行断言,因为如果测试失败,JUnit 异常会被 Javalin 吞噬,并且测试会悄无声息地失败 ()。解决方案是最后在外部进行断言,如 Arrange, Act, Assert 模式。
怎么样?您将要断言的内容存储在处理程序中,稍后再断言。例如,如果它是 POST.
var postedBody: String? = null
fakeProfileApi = Javalin.create().post("profile") {
postedBody = it.body()
}.start(1234)
val profileGateway = ProfileGateway(apiUrl = "http://localhost:1234")
profileGateway.saveProfile( // contains the HTTP POST
Profile(id = "abc", email = "john.doe@gmail.com".toEmail())
)
JSONAssert.assertEquals(
""" { "id": "abc", "email": "johndoe@gmail.com" } """,
postedBody, true
)
如果是 GET,则更容易:
fakeProfileApi = Javalin.create().get("profile/abc") {
it.result(""" {"id": "abc", "email": "johndoe@gmail.com"} """)
}.start(1234)
val profileGateway = ProfileGateway(apiUrl = "http://localhost:1234")
val result = profileGateway.fetchProfile("abc") // contains the HTTP GET
assertEquals(
Profile(id = "abc", email = "john.doe@gmail.com".toEmail()),
result
)
我有这个测试在端口 7000
启动服务,在唯一的端点内我做了一个失败的断言:
@Test
fun `javalin assertion should fail`() {
Javalin.create()
.get("/") { assertTrue(false) }
.start()
newHttpClient().send(
HttpRequest.newBuilder()
.uri(URI.create("http://localhost:7000/"))
.GET().build(),
discarding()
)
}
问题是测试总是通过(但应该会失败):
(运行ning ./gradlew test
发生同样的行为)
...即使控制台输出声称测试失败:
[Test worker] INFO io.javalin.Javalin - Listening on http://localhost:7000/
[Test worker] INFO io.javalin.Javalin - Javalin started in 356ms \o/
[qtp2100106358-22] ERROR io.javalin.Javalin - Exception occurred while servicing http-request
org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
..
可能 运行 在另一个线程中,但我想知道是否有办法将它附加到相同的上下文中。 (奇怪的是,在我的应用程序的另一个场景中——我无法隔离——它正常地失败了。)
TLDR
要使测试如您预期的那样失败,请在您从 Javalin 实例获得的响应上添加一个断言。
@Test
fun `javalin assertion should fail`() {
Javalin.create()
.get("/") { assertTrue(false) } // or any expression that throws an Exception, like Kotlin's TODO()
.start()
val javalinResponse: HttpResponse<Void> = newHttpClient().send(
HttpRequest.newBuilder()
.uri(URI.create("http://localhost:7000/"))
.GET().build(),
discarding()
)
assertThat(javalinResponse.statusCode()).isEqualTo(200) // will fail with Expected: 200, Actual: 500
}
详情
测试中有两个不同的步骤:新的 Javalin 实例配置 + 构建,以及使用 HttpClient 调用该实例。
在 Javalin 配置 + 构建步骤中,它被指示在 /
端点上调用时执行 assertTrue(false)
。 assertTrue(false)
将抛出一个 AssertionFailedError
,但如果你在那里抛出其他东西,行为将是相同的。现在,与许多(所有?)其他网络服务器一样,Javalin / Jetty 将尝试捕获其中发生的任何未捕获的异常和 return 代码为 500(内部服务器错误)的 HTTP 响应。
事实上,这一切都发生在另一个线程中,因为在内部启动了一个 Jetty 网络服务器实例,它执行端口侦听、HTTP 请求/响应处理和其他重要的事情。
因此,当稍后在测试中对新的 Javalin 实例执行 HTTP 调用时,它会成功获得 500(内部服务器错误)响应,并且最初没有对响应的断言并且没有未捕获的异常,测试成功。
永远不要在 Javalin 处理程序内部进行断言,因为如果测试失败,JUnit 异常会被 Javalin 吞噬,并且测试会悄无声息地失败 (
怎么样?您将要断言的内容存储在处理程序中,稍后再断言。例如,如果它是 POST.
var postedBody: String? = null
fakeProfileApi = Javalin.create().post("profile") {
postedBody = it.body()
}.start(1234)
val profileGateway = ProfileGateway(apiUrl = "http://localhost:1234")
profileGateway.saveProfile( // contains the HTTP POST
Profile(id = "abc", email = "john.doe@gmail.com".toEmail())
)
JSONAssert.assertEquals(
""" { "id": "abc", "email": "johndoe@gmail.com" } """,
postedBody, true
)
如果是 GET,则更容易:
fakeProfileApi = Javalin.create().get("profile/abc") {
it.result(""" {"id": "abc", "email": "johndoe@gmail.com"} """)
}.start(1234)
val profileGateway = ProfileGateway(apiUrl = "http://localhost:1234")
val result = profileGateway.fetchProfile("abc") // contains the HTTP GET
assertEquals(
Profile(id = "abc", email = "john.doe@gmail.com".toEmail()),
result
)