feature: #6: Add cucumber test for article routes

This commit is contained in:
2019-08-01 00:58:41 +02:00
parent 7acb2b3e40
commit 63a50dcb92
9 changed files with 213 additions and 12 deletions

9
.idea/compiler.xml generated
View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel>
<module name="dcproject.main" target="11" />
<module name="dcproject.test" target="11" />
</bytecodeTargetLevel>
</component>
</project>

1
.idea/misc.xml generated
View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>

View File

@@ -38,6 +38,14 @@ dependencies {
implementation("net.pearx.kasechange:kasechange-jvm:1.1.0") implementation("net.pearx.kasechange:kasechange-jvm:1.1.0")
implementation("fr.postgresjson:postgresjson:$postgresjson_version") implementation("fr.postgresjson:postgresjson:$postgresjson_version")
testImplementation("io.ktor:ktor-server-tests:$ktor_version") testImplementation("io.ktor:ktor-server-tests:$ktor_version")
testImplementation("io.ktor:ktor-client-mock:$ktor_version")
testImplementation("io.ktor:ktor-client-mock-jvm:$ktor_version")
testImplementation("org.koin:koin-test:$koinVersion")
testImplementation("io.mockk:mockk:1.9")
testImplementation("org.junit.jupiter:junit-jupiter:5.5.0")
testImplementation("org.amshove.kluent:kluent:1.4")
testImplementation("io.cucumber:cucumber-java8:4.3.1")
testImplementation("io.cucumber:cucumber-junit:4.3.1")
} }
kotlin.sourceSets["main"].kotlin.srcDirs("src") kotlin.sourceSets["main"].kotlin.srcDirs("src")

View File

@@ -6,9 +6,10 @@ import org.koin.dsl.module
import java.io.File import java.io.File
import fr.dcproject.repository.Article as ArticleRepository import fr.dcproject.repository.Article as ArticleRepository
val config = Config()
@KtorExperimentalAPI @KtorExperimentalAPI
val Module = module { val Module = module {
val config = Config()
single { config } single { config }

View File

@@ -21,10 +21,17 @@ class Article(override var requester: Requester) : RepositoryI<ArticleEntity> {
} }
} }
fun find(page: Int = 1, limit: Int = 50, sort: String? = null, direction: Direction? = null, search: String? = null): Paginated<ArticleEntity> { fun find(
page: Int = 1,
limit: Int = 50,
sort: String? = null,
direction: Direction? = null,
search: String? = null
): Paginated<ArticleEntity> {
return requester return requester
.getFunction("find_articles") .getFunction("find_articles")
.select(page, limit, .select(
page, limit,
"sort" to sort?.toSnakeCase(), "sort" to sort?.toSnakeCase(),
"direction" to direction, "direction" to direction,
"search" to search "search" to search

25
test/RunCucumberTest.kt Normal file
View File

@@ -0,0 +1,25 @@
import cucumber.api.CucumberOptions
import cucumber.api.Scenario
import cucumber.api.java8.En
import cucumber.api.junit.Cucumber
import feature.Context
import io.ktor.server.testing.TestApplicationEngine
import io.ktor.server.testing.createTestEnvironment
import org.junit.runner.RunWith
import java.util.concurrent.TimeUnit
import feature.Context.Companion.current as contextCurrent
@RunWith(Cucumber::class)
@CucumberOptions(plugin = ["pretty"])
class RunCucumberTest: En {
init {
Before(-1) { scenario: Scenario ->
// config.database = "dc-projectg-test"
contextCurrent = Context(TestApplicationEngine(createTestEnvironment()) {}, scenario)
}
After { scenario: Scenario ->
contextCurrent.engine.stop(0L, 0L, TimeUnit.MILLISECONDS)
}
}
}

40
test/feature/Context.kt Normal file
View File

@@ -0,0 +1,40 @@
package feature
import cucumber.api.Scenario
import fr.dcproject.module
import io.ktor.application.Application
import io.ktor.server.testing.TestApplicationCall
import io.ktor.server.testing.TestApplicationEngine
import io.ktor.server.testing.TestApplicationRequest
class Context(
val engine: TestApplicationEngine,
val scenario: Scenario
) {
companion object {
lateinit var current: Context
}
init {
engine.start()
val moduleFunction: Application.() -> Unit = { module() }
val test: TestApplicationEngine.() -> Unit = {
moduleFunction(application)
}
engine.test()
}
var call: TestApplicationCall? = null
private val requestContextConfigurations: MutableList<TestApplicationRequest.() -> Unit> = mutableListOf()
fun setupRequest(testApplicationRequest: TestApplicationRequest) {
requestContextConfigurations.forEach {
it(testApplicationRequest)
}
}
fun setupNextRequests(requestContextConfiguration: TestApplicationRequest.() -> Unit) = requestContextConfigurations.add(requestContextConfiguration)
}
fun TestApplicationRequest.applyConfigurations() {
Context.current.setupRequest(this)
}

92
test/feature/Request.kt Normal file
View File

@@ -0,0 +1,92 @@
package feature
import com.google.gson.Gson
import cucumber.api.Scenario
import cucumber.api.java8.En
import io.cucumber.datatable.DataTable
import io.ktor.http.ContentType
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpMethod
import io.ktor.http.HttpStatusCode
import io.ktor.server.testing.TestApplicationCall
import io.ktor.server.testing.TestApplicationEngine
import io.ktor.server.testing.setBody
import org.junit.jupiter.api.Assertions.assertEquals
import org.koin.test.KoinTest
import org.opentest4j.AssertionFailedError
import kotlin.test.asserter
import feature.Context.Companion.current as currentContext
class Request: En, KoinTest {
init {
Before { scenario: Scenario ->
}
After { scenario: Scenario ->
}
When("I send a {string} request to {string} with body:") { method: String, uri: String, body: String ->
val test: TestApplicationEngine.() -> Unit = {
currentContext.call = handleRequest {
applyConfigurations()
addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
this.method = HttpMethod.parse(method)
this.uri = uri
setBody(body)
}
}
currentContext.engine.test()
}
When("I send a {string} request to {string}") { method: String, uri: String ->
val test: TestApplicationEngine.() -> Unit = {
currentContext.call = handleRequest {
applyConfigurations()
addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
this.method = HttpMethod.parse(method.toUpperCase())
this.uri = uri
}
}
currentContext.engine.test()
}
Then("the response status code should be {int}") { statusCode: Int ->
val call: TestApplicationCall = currentContext.call ?: throw AssertionFailedError("No call", statusCode, null)
with(call) {
assertEquals(HttpStatusCode.fromValue(statusCode), response.status())
}
}
And("the response should contain:") { expected: DataTable ->
val call: TestApplicationCall = currentContext.call ?: throw AssertionFailedError("No call")
val p = call.response
val response = Gson().fromJson<List<Map<String, String>>>(p.content, List::class.java)
expected.asMap<String, String>(String::class.java, String::class.java).forEach { (key, value) ->
response.forEach {
if (it.containsKey(key)) {
assertEquals(it[key], value)
return@And
}
}
asserter.fail("The response not contain $key field")
}
}
And("the response should contain object:") { expected: DataTable ->
val call: TestApplicationCall = currentContext.call ?: throw AssertionFailedError("No call")
val p = call.response
val response = Gson().fromJson<Map<String, String>>(p.content, Map::class.java)
expected.asMap<String, String>(String::class.java, String::class.java).forEach { (key, value) ->
if (response.containsKey(key)) {
assertEquals(value, response[key])
return@And
}
asserter.fail("The response not contain $key field")
}
}
}
}

View File

@@ -0,0 +1,36 @@
Feature: articles routes
Scenario: The route for get articles must response a 200
When I send a "GET" request to "/articles"
Then the response status code should be 200
Scenario: The route for get article must response a 200
When I send a "GET" request to "/articles/55a24426-139b-4ee7-b1e2-a3d016d66cc2"
Then the response status code should be 200
Scenario: The route for get article must response a 200
When I send a "POST" request to "/articles" with body:
"""
{
"version_id": "09c418b6-63ba-448b-b38b-502b41cd500e",
"title": "title2",
"annonymous": false,
"content": "content2",
"description": "description2",
"tags": [
"green"
],
"created_by": {
"id": "64b7b379-2298-43ec-b428-ba134930cabd"
}
}
"""
Then the response status code should be 200
And the response should contain object:
| version_id | 09c418b6-63ba-448b-b38b-502b41cd500e |
| title | title2 |
When I send a "GET" request to "/articles/99afd1b1-3555-43c1-80a7-63c56e93d250"
Then the response status code should be 200
And the response should contain object:
| id | 99afd1b1-3555-43c1-80a7-63c56e93d250 |
| title | title2 |