Merge pull request #90 from flecomte/improve-test

Improve tests
This commit was merged in pull request #90.
This commit is contained in:
2021-04-03 00:39:16 +02:00
committed by GitHub
21 changed files with 52 additions and 32 deletions

View File

@@ -0,0 +1,4 @@
package fr.dcproject.common.utils
fun String.isInt(): Boolean = this.toIntOrNull() != null
fun String.isBool(): Boolean = this == "true" || this == "false"

View File

@@ -0,0 +1,7 @@
package assert
import kotlin.test.assertTrue
infix fun IntProgression.assertContain(expected: Int) {
assertTrue(this.contains(expected), "Expected $this less than $expected")
}

View File

@@ -22,7 +22,7 @@ import org.koin.test.get
@KtorExperimentalLocationsAPI
@KtorExperimentalAPI
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Tags(Tag("functional"))
@Tags(Tag("functional"), Tag("mail"))
class MailerTest : KoinTest, AutoCloseKoinTest() {
@InternalCoroutinesApi
@ExperimentalCoroutinesApi

View File

@@ -33,7 +33,7 @@ import org.junit.jupiter.api.TestInstance
import org.slf4j.LoggerFactory
@TestInstance(TestInstance.Lifecycle.PER_METHOD)
@Tags(Tag("functional"))
@Tags(Tag("functional"), Tag("notification"))
class NotificationConsumerTest {
companion object {
@BeforeAll

View File

@@ -24,7 +24,7 @@ import org.junit.jupiter.api.Tags
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
@Tags(Tag("functional"))
@Tags(Tag("functional"), Tag("notification"))
internal class NotificationsPushTest {
companion object {
@BeforeAll

View File

@@ -8,7 +8,7 @@ import org.junit.jupiter.api.TestInstance
import kotlin.test.assertEquals
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Tags(Tag("functional"))
@Tags(Tag("functional"), Tag("utils"))
class ResourcesKtTest {
@Test
fun readResource() {

View File

@@ -25,7 +25,7 @@ import java.util.UUID
@KtorExperimentalAPI
@ExperimentalCoroutinesApi
@TestInstance(PER_CLASS)
@Tags(Tag("functional"))
@Tags(Tag("functional"), Tag("view"))
class ViewTest {
@Test
fun `test View Article`() {

View File

@@ -38,7 +38,7 @@ class `Article routes` : BaseTest() {
`And the response should contain pattern`("$.result[1].createdBy.name.firstName", "firstName.+")
`And the response should contain pattern`("$.result[2].createdBy.name.firstName", "firstName.+")
`And the response should not contain`("$.result[3]")
`And the response should contain list`("$.result", 3, 3)
`And the response should contain list`("$.result", 3)
}
}
}

View File

@@ -57,7 +57,7 @@ class `Comment constitutions routes` : BaseTest() {
`And the response should contain`("$.limit", 50)
`And the response should contain`("$.result[0].createdBy.id", "46e0bda9-ca6a-4c65-a58b-7e7267a0bbc5")
`And the response should contain`("$.result[0].target.id", "34ddd50a-da00-4a90-a869-08baa2a121be")
`And the response should contain list`("$.result[*]", 1, 1)
`And the response should contain list`("$.result[*]", 1)
}
}
}

View File

@@ -21,7 +21,7 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Tags(Tag("integration"), Tag("article"), Tag("opinion"))
@Tags(Tag("integration"), Tag("opinion"))
class `Opinion routes` : BaseTest() {
@Test
fun `I can get all opinion choices`() {
@@ -48,6 +48,7 @@ class `Opinion routes` : BaseTest() {
}
@Test
@Tag("article")
fun `I can create opinion on article`() {
withIntegrationApplication {
`Given I have citizen`("Isaac", "Newton", id = "2f414045-95d9-42ca-a3a9-8cdde52ad253")
@@ -89,6 +90,7 @@ class `Opinion routes` : BaseTest() {
}
@Test
@Tag("article")
fun `I can receive opinion aggregation with article`() {
withIntegrationApplication {
`Given I have an opinion choice`("Opinion6")
@@ -120,6 +122,7 @@ class `Opinion routes` : BaseTest() {
}
@Test
@Tag("article")
fun `I can get all my opinion of one article`() {
withIntegrationApplication {
`Given I have citizen`("Albert", "Einstein", id = "c1542096-3431-432d-8e35-9dc071d4c818")
@@ -134,7 +137,7 @@ class `Opinion routes` : BaseTest() {
`authenticated as`("Albert", "Einstein")
} `Then the response should be` OK and {
`And the response should contain`("$.result[0].name", "Opinion9")
`And the response should contain list`("$.result[*]", 1, 1)
`And the response should contain list`("$.result[*]", 1)
}
}
}

View File

@@ -119,7 +119,7 @@ class `Workgroup routes` : BaseTest() {
`And the response should contain`("$.description", "Une petite souris")
`And have property`("$.members")
`And the response should contain list`("$.members", 3, 3)
`And the response should contain list`("$.members", 3)
`And the response should contain`("$.members.[1]citizen.id", "94f92424-c257-4582-907c-98564a8c4ac9")
`And the response should contain`("$.members.[2]citizen.id", "87909ba3-2069-431c-9924-219fd8411cf2")
}
@@ -215,7 +215,7 @@ class `Workgroup routes` : BaseTest() {
]
"""
} `Then the response should be` OK and {
`And the response should contain list`("$", 2, 2)
`And the response should contain list`("$", 2)
`And the response should contain`("$.[0]citizen.id", "94f92424-c257-4582-907c-98564a8c4ac9")
`And the response should contain`("$.[1]citizen.id", "1baf48bb-02bc-4d8f-ac86-33335354f5e7")
}
@@ -252,7 +252,7 @@ class `Workgroup routes` : BaseTest() {
"""
)
} `Then the response should be` OK and {
`And the response should contain list`("$", 2, 2)
`And the response should contain list`("$", 2)
`And the response should contain`("$.[0]citizen.id", "be3b0926-8628-4426-804a-75188a6eb315")
`And the response should contain`("$.[1]citizen.id", "b49e20c1-8393-45d6-a6a0-3fa5c71cbdc1")
}

View File

@@ -1,7 +1,6 @@
package integration.steps.then
import assert.assertGreaterThan
import assert.assertLessThan
import assert.assertContain
import com.jayway.jsonpath.JsonPath
import com.jayway.jsonpath.PathNotFoundException
import io.ktor.http.HttpStatusCode
@@ -85,15 +84,13 @@ fun TestApplicationResponse.`And the response should contain pattern`(path: Stri
}
}
fun TestApplicationResponse.`And the response should contain list`(path: String, min: Int? = null, max: Int? = null) {
fun TestApplicationResponse.`And the response should contain list`(path: String, exactCount: Int) =
`And the response should contain list`(path, IntRange(exactCount, exactCount))
fun TestApplicationResponse.`And the response should contain list`(path: String, range: IntRange) {
JsonPath.read<JSONArray?>(content, path).also {
assertNotNull(it)
if (min != null) {
it.size assertGreaterThan min
}
if (max != null) {
it.size assertLessThan max
}
range assertContain it.size
}
}

View File

@@ -2,8 +2,12 @@ package integration.steps.then
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.BooleanNode
import com.fasterxml.jackson.databind.node.IntNode
import com.fasterxml.jackson.databind.node.TextNode
import fr.dcproject.common.utils.getResource
import fr.dcproject.common.utils.isBool
import fr.dcproject.common.utils.isInt
import io.ktor.http.ContentType
import io.ktor.http.Url
import io.ktor.request.contentType
@@ -55,15 +59,15 @@ fun TestApplicationResponse.`And the schema response body must be valid`(content
/* Validate Response */
this.apply {
val status = call.response.status()
val httpMethod = call.request.httpMethod.value.toUpperCase()
val responseContent: JsonNode = if (content != null)
ObjectMapper().readTree(content)
else TextNode("")
val response = getResponse(status?.value?.toString() ?: error("HttpStatus not found")) ?: fail("""No Status "${status.value}" found for "$this $uri".""")
val response = getResponse(status?.value?.toString() ?: error("HttpStatus not found")) ?: fail("""No Status "${status.value}" found for "$httpMethod $uri".""")
val schema = response.getContentMediaType(contentType.toString())?.schema
if (content != null) {
val httpMethod = call.request.httpMethod.value
schema?.validate(api, responseContent)
?: fail("""No Status "${status.value}" found with media type "$contentType" for "$httpMethod $uri".""")
}
@@ -75,13 +79,18 @@ fun TestApplicationResponse.`And the schema parameters must be valid`() {
operation { api, uri ->
/* Validate Request URL */
this.apply {
val methodName = call.request.httpMethod.value.toUpperCase()
Url(call.request.uri).parameters.forEach { parameter: String, values: List<String> ->
val schema = getParametersIn(api.context, "query")
?.firstOrNull { it.name == parameter }?.schema
?: error("""No parameter found ($parameter) for "$this $uri".""")
?: error("""No parameter found ($parameter) for "$methodName $uri".""")
if (schema.type == "array") {
schema.validate(api, ObjectMapper().valueToTree(values))
} else if (schema.type == "integer" && values.first().isInt()) {
schema.validate(api, IntNode(values.first().toInt()))
} else if (schema.type == "boolean" && values.first().isBool()) {
schema.validate(api, BooleanNode.valueOf(values.first().toBoolean()))
} else {
schema.validate(api, TextNode(values.first()))
}

View File

@@ -27,7 +27,7 @@ import fr.dcproject.component.article.database.ArticleRepository as ArticleRepo
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Execution(CONCURRENT)
@Tags(Tag("security"), Tag("unit"))
@Tags(Tag("security"), Tag("unit"), Tag("article"))
internal class `Article Access Control` {
private val tesla = CitizenCreator(
id = UUID.fromString("e6efc288-4283-4729-a268-6debb18de1a0"),

View File

@@ -18,7 +18,7 @@ import org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Execution(CONCURRENT)
@Tags(Tag("security"), Tag("unit"))
@Tags(Tag("security"), Tag("unit"), Tag("citizen"))
internal class `Citizen Access Control` {
private val tesla = CitizenCart(
user = User(

View File

@@ -25,7 +25,7 @@ import java.util.UUID
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Execution(CONCURRENT)
@Tags(Tag("security"), Tag("unit"))
@Tags(Tag("security"), Tag("unit"), Tag("comment"))
internal class `Comment Access Control` {
private val tesla = Citizen(
user = User(

View File

@@ -23,7 +23,7 @@ import java.util.UUID
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Execution(CONCURRENT)
@Tags(Tag("security"), Tag("unit"))
@Tags(Tag("security"), Tag("unit"), Tag("follow"))
internal class `Follow Access Control` {
private val tesla = CitizenCreator(
user = UserCreator(

View File

@@ -21,7 +21,7 @@ import java.util.UUID
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Execution(CONCURRENT)
@Tags(Tag("security"), Tag("unit"))
@Tags(Tag("security"), Tag("unit"), Tag("opinion"))
internal class `Opinion Access Control` {
private val tesla = CitizenCreator(
user = UserCreator(

View File

@@ -15,7 +15,7 @@ import java.util.UUID
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Execution(CONCURRENT)
@Tags(Tag("security"), Tag("unit"))
@Tags(Tag("security"), Tag("unit"), Tag("opinion"))
internal class `OpinionChoice Access Control` {
private val tesla = CitizenRef(
id = UUID.fromString("e6efc288-4283-4729-a268-6debb18de1a0"),

View File

@@ -24,7 +24,7 @@ import java.util.UUID
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Execution(CONCURRENT)
@Tags(Tag("security"), Tag("unit"))
@Tags(Tag("security"), Tag("unit"), Tag("vote"))
internal class `Vote Access Control` {
private val tesla = Citizen(
id = UUID.fromString("a1e35c99-9d33-4fb4-9201-58d7071243bb"),

View File

@@ -20,7 +20,7 @@ import fr.dcproject.component.workgroup.database.WorkgroupForView as WorkgroupEn
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Execution(CONCURRENT)
@Tags(Tag("security"), Tag("unit"))
@Tags(Tag("security"), Tag("unit"), Tag("workgroup"))
internal class `Workgroup Access Control` {
private val tesla = CitizenCreator(
user = UserCreator(