'Kotlin how to create custom assertion with assertj
I'd like to create custom assertion in the same file of my test code.
What I did is
fun String?.isValidJson(): Boolean {
try {
JSONObject(this)
} catch (ex: JSONException) {
// e.g. in case JSONArray is valid as well...
try {
JSONArray(this)
} catch (ex1: JSONException) {
return false
}
}
return true
}
@Test
fun `Check body is valid json`() {
// ...
assertThat(entity.body.isValidJson()).isTrue()
}
However, it look not professional and I want to customize my own assertion:
assertThat(entity.body).isValidJson()
I tried in many ways with helps of IntelliJ, but it all failed. Could anyone can create this?
This is automatically generated function by IntelliJ which not works:
private fun <SELF, ACTUAL> AbstractCharSequenceAssert<SELF, ACTUAL>.isValidJson() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
Solution 1:[1]
As described here (official AssertJ documentation), you can get the result you want with something like
import JsonAssert.Companion.assertThatJson
import org.assertj.core.api.AbstractAssert
import org.junit.Test
fun String?.isValidJson(): Boolean {
// return this == "valid"
try {
JSONObject(this)
} catch (ex: JSONException) {
// e.g. in case JSONArray is valid as well...
try {
JSONArray(this)
} catch (ex1: JSONException) {
return false
}
}
return true
}
class JsonAssert(value: String) : AbstractAssert<JsonAssert, String>(value, JsonAssert::class.java) {
fun isValid() : JsonAssert {
if(!actual.isValidJson()) {
failWithMessage("Actual value <%s> is not a valid JSON", actual);
}
return this
}
companion object {
fun assertThatJson(value: String) : JsonAssert {
return JsonAssert(value)
}
}
}
class ScratchTest {
@Test
fun `Check body is valid json`() {
val value = "valid"
assertThatJson(value).isValid()
}
}
I assumed your implementation of fun String?.isValidJson(): Boolean is ok and reused it in my custom assertion class. For testing purposes, you can change it decommenting the first line and commentind the rest of the function, in order to focus on custom assertion implementation...
I hope this can help you to achieve your goal!
Solution 2:[2]
Given that there's no way of getting the actual value from the AssertJ class without extending it, I decided to call it with its satisfies(Consumer<String> condition) validation, which will pass the actual value to a lambda and, ultimately, save it to a local variable. Then you can use the value to call your isValidJson() function (or JSONAssert directly, if you wish).
import org.assertj.core.api.AbstractStringAssert
import java.util.function.Consumer
fun AbstractStringAssert<*>.isValidJsonString() {
var value: String? = null
val consumer: Consumer<String> = Consumer<String> { value = it }
satisfies(consumer)
value.isValidJson() // This is your function
}
While this is not a fully-fledged AssertJ assertion, it is far easier to implement and allows us using the same assertThat() instead of having to write new ones. Also, in my case, I'd prefer to be able to use always AssertJ's assertThat() function instead of having to import different assertion names as the AssertJ documentation suggests.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Pietro Martinelli |
| Solution 2 | Igor Rodriguez |
