org.http4k.testing.ApprovalTest.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of http4k-testing-approval Show documentation
Show all versions of http4k-testing-approval Show documentation
Http4k support for Approval Testing
package org.http4k.testing
import com.github.underscore.Json
import com.github.underscore.Json.JsonStringBuilder.Step.TWO_SPACES
import com.github.underscore.Json.formatJson
import com.github.underscore.Xml.formatXml
import org.http4k.core.CLOUD_EVENT_JSON
import org.http4k.core.ContentType
import org.http4k.core.ContentType.Companion.APPLICATION_JSON
import org.http4k.core.ContentType.Companion.APPLICATION_XML
import org.http4k.core.ContentType.Companion.APPLICATION_YAML
import org.http4k.core.ContentType.Companion.TEXT_HTML
import org.http4k.core.HttpMessage
import org.http4k.format.JacksonYaml
import org.http4k.lens.Header.CONTENT_TYPE
import org.http4k.testing.ApprovalContent.Companion.HttpBinaryBody
import org.http4k.testing.ApprovalContent.Companion.HttpTextBody
import org.http4k.testing.TestNamer.Companion.ClassAndMethod
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback
import org.junit.jupiter.api.extension.ExtensionContext
import org.junit.jupiter.api.extension.ExtensionContext.Namespace.create
import org.junit.jupiter.api.extension.ParameterContext
import org.junit.jupiter.api.extension.ParameterResolver
import org.opentest4j.AssertionFailedError
import java.io.File
/**
* Base JUnit extension for injecting an Approver into a JUnit5 test-case. Implement this
* to provide custom approval behaviours, or
*/
interface BaseApprovalTest : BeforeTestExecutionCallback, ParameterResolver {
fun approverFor(context: ExtensionContext): Approver
override fun beforeTestExecution(context: ExtensionContext) = store(context).put("approver", approverFor(context))
override fun supportsParameter(parameterContext: ParameterContext, context: ExtensionContext) =
parameterContext.parameter.type == Approver::class.java
override fun resolveParameter(parameterContext: ParameterContext, context: ExtensionContext) =
if (supportsParameter(parameterContext, context)) store(context)["approver"] else null
private fun store(context: ExtensionContext) = with(context) {
getStore(create(requiredTestClass.name, requiredTestMethod.name))
}
}
/**
* Standard Approval JUnit5 extension. Can be used to compare any HttpMessages.
*/
class ApprovalTest : BaseApprovalTest {
override fun approverFor(context: ExtensionContext): Approver = NamedResourceApprover(
ClassAndMethod.nameFor(context.requiredTestClass, context.requiredTestMethod),
HttpTextBody(),
FileSystemApprovalSource(File("src/test/resources"))
)
}
/**
* Approval testing JUnit5 extension that checks the expected content type is present in the
*/
abstract class ContentTypeAwareApprovalTest(
private val contentType: ContentType,
private val testNamer: TestNamer = ClassAndMethod,
private val approvalSource: ApprovalSource = FileSystemApprovalSource(File("src/test/resources"))
) : BaseApprovalTest {
override fun approverFor(context: ExtensionContext) = checkingContentType(
NamedResourceApprover(
testNamer.nameFor(context.requiredTestClass, context.requiredTestMethod),
HttpTextBody(::format),
approvalSource
),
contentType
)
abstract fun format(input: String): String
}
fun checkingContentType(approver: Approver, contentType: ContentType): Approver = object : Approver {
override fun assertApproved(httpMessage: T) {
println("checking approved")
approver.assertApproved(httpMessage)
println("checking content type")
println(contentType)
println(CONTENT_TYPE(httpMessage))
println(httpMessage)
assertEquals(contentType, CONTENT_TYPE(httpMessage))
}
override fun withNameSuffix(suffix: String) =
checkingContentType(approver.withNameSuffix(suffix), contentType)
}
/**
* Approval JUnit5 extension configured to compare prettified-JSON messages.
*/
class JsonApprovalTest(
testNamer: TestNamer = ClassAndMethod,
approvalSource: ApprovalSource = FileSystemApprovalSource(File("src/test/resources"))
) : ContentTypeAwareApprovalTest(APPLICATION_JSON, testNamer, approvalSource) {
override fun format(input: String): String = try {
formatJson(input, TWO_SPACES)
} catch (e: Json.ParseException) {
throw AssertionFailedError("Invalid JSON generated", "", input, e)
}
}
/**
* Approval JUnit5 extension configured to compare prettified-JSON messages.
*/
class CloudEventsJsonApprovalTest(
testNamer: TestNamer = ClassAndMethod,
approvalSource: ApprovalSource = FileSystemApprovalSource(File("src/test/resources"))
) : ContentTypeAwareApprovalTest(ContentType.CLOUD_EVENT_JSON, testNamer, approvalSource) {
override fun format(input: String): String = try {
formatJson(input, TWO_SPACES)
} catch (e: Json.ParseException) {
throw AssertionFailedError("Invalid JSON generated", "", input, e)
}
}
/**
* Approval JUnit5 extension configured to compare prettified-HTML messages. Note that this strips
* ", input, e)
}
}
/**
* Approval JUnit5 extension configured to compare prettified-XML messages.
*/
class XmlApprovalTest(
testNamer: TestNamer = ClassAndMethod,
approvalSource: ApprovalSource = FileSystemApprovalSource(File("src/test/resources"))
) : ContentTypeAwareApprovalTest(APPLICATION_XML, testNamer, approvalSource) {
override fun format(input: String): String = try {
formatXml(input)
} catch (e: IllegalArgumentException) {
throw AssertionFailedError("Invalid XML generated", "", input, e)
}
}
/**
* Approval JUnit5 extension configured to compare prettified-YAML messages.
*/
class YamlApprovalTest(
testNamer: TestNamer = ClassAndMethod,
approvalSource: ApprovalSource = FileSystemApprovalSource(File("src/test/resources"))
) : ContentTypeAwareApprovalTest(APPLICATION_YAML, testNamer, approvalSource) {
override fun format(input: String): String = try {
JacksonYaml.asA