kTest
kTest is integration / acceptance / system / any other non-unit test oriented modular test framework in Kotlin. Inspired by kotlintest, specs2 and martians.
Usage
Styling your test
object MyTestSpecification : BehaviorSpec({
given("some service") {
`when`("executing it's API") {
then("it should work correctly") {
// test body...
}
}
}
})
Performing simple HTTP
fun makeMyHttp(): List<Account> {
return rest["my-backend"] {
using(url) {
agreements / param("id") / accounts
} execute {
GET(pathParam(123), header("Accept", "application/json"))
}
}
}
Working with JSON
fun loadAccounts(resourcePath: String) =
resourcePath.loadAsJson { list(map<String, Any>()) }.also {
println(it.dump()) // pretty-printing pseudo-logging
}
Matching over JSON
fun compareMyJsons(expected: JsonNode, actual: JsonNode) {
with(JsonNodeMatchers) {
assertThat(actual, isIdenticalTo(expected).bySubtree {
// comparing only meaningful nodes
"accounts[*]" {
+ "id"
+ "accountNumber"
"owner" {
+ "id"
+ "name"
}
}
})
}
}
Searching over JSON
Powered by JSONPath
fun allIdsNearAccountNumbers(jp: DocumentContext) =
jp select "id" where {
"accountNumber".exists()
} castTo { list<Long>() }
Accessing database
fun getAccounts(activeOn: Date) =
"my-database".db {
select<Account>("""
| SELECT * FROM accounts
| WHERE
| close_date is NULL
| OR close_date < :activeOn
""".trimMargin()) {
parameter("activeOn", activeOn)
}.asList()
}
REST specification
object MyTest : SimpleSpec({
suite("my service suite") {
restTest(name = { "${it.method} accounts" }) {
url { agreements / accounts }
GET(queryParam("name", "%"))
POST(body("name", "%")) { it / search }
expect { response: DocumentContext ->
// do some check
}
}
}
})
Configuring reporting engine
Reporting powered by excellent Allure
object MyTest : AllureSpec({
feature("some feature", metaInfo = {
blocker()
}) {
story("true story", metaInfo = {
issue("PROJ-111")
}) {
case("my case", metaInfo = {
description("my description")
}) {
// test body...
}
}
}
})
Putting it all together
object AccountByCustomerRestApiSpec : AllureSpec({
beforeAll {
rest["backend"] {
using(url) {
`internal` / caches
} execute {
DELETE(queryParam("force", "true"))
}
}
}
epic("Search") {
feature("Account by customer search") {
story("Single criteria search") {
val testTable = table(
header("criteriaName", "criteriaValue", "expectedJsonName"),
row("billing", ">100", "richAccounts.json"),
row("region", "Central", "centralRegionAccounts.json"),
row("validTill", ">${LocalDate.now().format(DateTimeFormatter.ISO_DATE)}", "activeAccounts.json")
)
// should be generated right before test
val myGeneratedCustomer: Customer = testData["customer.json"]
forAll(testTable) { criteriaName, criteriaValue, expectedJsonName ->
val criteria = mapOf<String, String>(
criteriaName, criteriaValue
)
restTest(name = { "Search account by \"$criteriaName\": ${it.method}" }, metaData = {
category<Complex>()
flaky()
}) {
url { customers / param("customerId") / accounts }
GET(queryParams(criteria), pathParam("customerId", myGeneratedCustomer.id))
POST(body(criteria), pathParam("customerId", myGeneratedCustomer.id))
expect { response: DocumentContext ->
with(DocumentContextMatchers) {
assertThat(response, matches(expectedJsonName.loadAsJsonPath()).afterRemovalOfSubtree {
"account[].metaData" {
+ "date"
+ "IP"
}
})
}
}
}
}
}
}
}
})
Download
You can use dependency management
Gradle
compile 'run.smt.ktest:ktest-api'
compile 'run.smt.ktest:ktest-config'
compile 'run.smt.ktest:ktest-util'
compile 'run.smt.ktest:ktest-runner-junit4'
compile 'run.smt.ktest:ktest-allure'
compile 'run.smt.ktest:ktest-jackson'
compile 'run.smt.ktest:ktest-json-matchers'
compile 'run.smt.ktest:ktest-jsonpath'
compile 'run.smt.ktest:ktest-db'
compile 'run.smt.ktest:ktest-rest'
compile 'run.smt.ktest:ktest-resttest'
Maven
<dependency>
<groupId>run.smt.ktest</groupId>
<artifactId>ktest-api</artifactId>
</dependency>
<dependency>
<groupId>run.smt.ktest</groupId>
<artifactId>ktest-config</artifactId>
</dependency>
<dependency>
<groupId>run.smt.ktest</groupId>
<artifactId>ktest-util</artifactId>
</dependency>
<dependency>
<groupId>run.smt.ktest</groupId>
<artifactId>ktest-runner-junit4</artifactId>
</dependency>
<dependency>
<groupId>run.smt.ktest</groupId>
<artifactId>ktest-allure</artifactId>
</dependency>
<dependency>
<groupId>run.smt.ktest</groupId>
<artifactId>ktest-jackson</artifactId>
</dependency>
<dependency>
<groupId>run.smt.ktest</groupId>
<artifactId>ktest-json-matchers</artifactId>
</dependency>
<dependency>
<groupId>run.smt.ktest</groupId>
<artifactId>ktest-jsonpath</artifactId>
</dependency>
<dependency>
<groupId>run.smt.ktest</groupId>
<artifactId>ktest-db</artifactId>
</dependency>
<dependency>
<groupId>run.smt.ktest</groupId>
<artifactId>ktest-rest</artifactId>
</dependency>
<dependency>
<groupId>run.smt.ktest</groupId>
<artifactId>ktest-resttest</artifactId>
</dependency>
License
All source code is licensed under MIT license