Ktor testing Fail to serialize body. Content has type: class ... but OutgoingContent expected - kotlin

so trying to understand how I can make testing ktor app with testcontainers
this is my code
package com.app
import com.app.base.db.DbFactory
import com.app.features.auth.RegisterDTO
import com.app.plugins.*
import io.kotest.assertions.ktor.client.shouldHaveStatus
import io.kotest.core.extensions.install
import io.kotest.core.spec.style.FreeSpec
import io.kotest.extensions.testcontainers.JdbcTestContainerExtension
import io.ktor.client.*
import io.ktor.client.engine.apache.*
import io.ktor.client.request.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
import io.ktor.server.plugins.contentnegotiation.*
import org.testcontainers.containers.PostgreSQLContainer
import io.ktor.server.testing.*
import kotlinx.serialization.json.Json
import org.jetbrains.exposed.sql.Database
class AuthSpec : FreeSpec({
val postgres = PostgreSQLContainer<Nothing>("postgres").apply {
withDatabaseName("test_appDB")
startupAttempts = 1
withUsername("test_viktor")
withPassword("test_longPass")
withExposedPorts(5432)
}
postgres.start()
val ds = install(JdbcTestContainerExtension(postgres)) {
poolName = "myconnectionpool"
maximumPoolSize = 8
idleTimeout = 10000
}
"register creator" - {
testApplication {
application {
DbFactory.init(ds)
configureSecurity()
configureHTTP()
configureMonitoring()
configureSerialization()
configureDependencyInjection()
configureStatusPage()
configureRouting()
}
val client = HttpClient(Apache) {}
client.post("/api/v1/auth/register") {
contentType(ContentType.Application.Json)
setBody(RegisterDTO("some#gmail.com", "some", "some#sdfSDF"))
}.apply {
this.shouldHaveStatus(HttpStatusCode.OK)
}
}
}
})
I do expect that this test will run correctly and I can see the green in tests but actually i see the error
Fail to serialize body. Content has type: class com.app.features.auth.RegisterDTO, but OutgoingContent expected.
java.lang.IllegalStateException: Fail to serialize body. Content has type: class com.app.features.auth.RegisterDTO, but OutgoingContent expected.
If you expect serialized body, please check that you have installed the corresponding plugin(like `ContentNegotiation`) and set `Content-Type` header.
at io.ktor.client.plugins.HttpSend$Plugin$install$1.invokeSuspend(HttpSend.kt:87)
at io.ktor.client.plugins.HttpSend$Plugin$install$1.invoke(HttpSend.kt)
at io.ktor.client.plugins.HttpSend$Plugin$install$1.invoke(HttpSend.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:123)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:81)
at io.ktor.util.pipeline.SuspendFunctionGun.proceedWith(SuspendFunctionGun.kt:91)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invokeSuspend(HttpCallValidator.kt:126)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(HttpCallValidator.kt)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(HttpCallValidator.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:123)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:81)
at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invokeSuspend(HttpRequestLifecycle.kt:35)
at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(HttpRequestLifecycle.kt)
at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(HttpRequestLifecycle.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:123)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:81)
at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:101)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
at io.ktor.client.HttpClient.execute$ktor_client_core(HttpClient.kt:187)
at io.ktor.client.statement.HttpStatement.executeUnsafe(HttpStatement.kt:107)
at io.ktor.client.statement.HttpStatement.execute(HttpStatement.kt:46)
at io.ktor.client.statement.HttpStatement.execute(HttpStatement.kt:61)
at com.app.AuthSpec$1$1$1.invokeSuspend(AuthSpec.kt:84)
i have installed a lot of libraries for tests probably they are not needed but here are they in dependendancies
//region tests
testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
testImplementation("io.ktor:ktor-server-test-host:$ktor_version")
testImplementation("org.jetbrains.kotlin:kotlin-test:$kotlin_version")
testImplementation("io.kotest:kotest-runner-junit5:$kotest_version")
testImplementation("io.kotest:kotest-assertions-core:$kotest_version")
testImplementation("io.kotest:kotest-property:$kotest_version")
testImplementation("io.kotest.extensions:kotest-extensions-testcontainers:1.3.2")
testImplementation("org.testcontainers:testcontainers:$testcontainers_version")
testImplementation("org.testcontainers:junit-jupiter:$testcontainers_version")
testImplementation("org.testcontainers:postgresql:$testcontainers_version")
testImplementation("io.kotest.extensions:kotest-assertions-ktor:1.0.3")
//endregion

You need to install the ContentNegotiation plugin by configuring the test client.

Related

Test koin in ktor application

Hi im trying to write ktor testcases with koin dependency injection and in the tutorial im watching the person uses withTestApplication(moduleFunction = {install(Routing)}) Though withTestApplication() is deprecated and so the moduleFunction part does not work with the new testApplication() setup what should i do instead is my question? this is the tutorial im watching Tutorial
i have also checked
https://ktor.io/docs/migrating-2.html#testing-api
and
https://insert-koin.io/docs/reference/koin-test/testing
To configure a module using testApplication use the application method:
import io.ktor.server.application.*
import io.ktor.server.routing.*
import io.ktor.server.testing.*
import kotlin.test.Test
class KtorTest {
#Test
fun test() = testApplication {
application {
install(Routing)
}
}
}

Ktor application not running on my computer

I am trying to learn to use ktor and I'm trying to display the text "Hello Ktor" at the root path but all I keep getting is this site can't be reached.
This is my code:
import io.ktor.application.*
import io.ktor.http.ContentType
import io.ktor.response.respondText
import io.ktor.routing.get
import io.ktor.routing.routing
fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
private val userData = "{\"users\": [\"Timi\", \"Tomi\", \"Temi\"]}"
#Suppress("unused") // Referenced in application.conf
#kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
routing {
get("/") {
call.respondText("Hello Ktor", ContentType.Text.Plain)
}
}
}
What am I doing wrong?
Your code is fine.
I think you just need to access it correctly from browser.
Try
127.0.0.1:8080
or
localhost:8080
or simply follow nice tutorial from official website.
Are you trying to run without a main?
Did you follow this guide? https://ktor.io/quickstart/quickstart/gradle.html#intellij-extract-out-configuration-data
If you want to start from main, use embeddedServer. Otherwise you have to set the mainClassName.

Why is my Micronaut Controller bean not handled during tests

I am trying to use micronaut from Kotlin. I have this:
package me.test
import io.micronaut.http.MediaType
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.annotation.Produces
#Controller("/hello")
class Controller() {
#Get("/")
#Produces(MediaType.TEXT_PLAIN)
fun ping(): String {
return "hello world"
}
}
package me.test
import io.micronaut.runtime.Micronaut
object Application {
#JvmStatic
fun main(args: Array<String>) {
Micronaut.build()
.packages("me.test")
.mainClass(Application.javaClass)
.start()
}
}
I wrote the following controller test:
package me.test
import io.micronaut.http.client.RxHttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.test.annotation.MicronautTest
import org.junit.jupiter.api.Test
import javax.inject.Inject
#MicronautTest(application = Application::class)
class ControllerTest {
#Inject
#field:Client("/")
private lateinit var client: RxHttpClient
#Test
fun `should server ping with a pong`() {
val result = client.toBlocking().retrieve("/hello")
println(result)
}
}
but the test fails with a HttpClientResponseException: Page Not Found.
I have debugged this and from what I can tell, during the test, in DefaultBeanContext.getBeanDefinitions it doesn't find any beans for the #Controller qualifier. When I start the application using my Application class, I can see that it finds the Controller and makes the route available.
This is pretty much the Hello World for Micronaut, I am not sure what's going wrong here.
I think this is purely IDE related. I have Intellij set up to use Annotation Processors, to delegate builds to Gradle and to use the Gradle Test Runner. However, you also need to delete any existing test configurations and then the problem goes away.

How to load all dependencies in Main.js using Aurelia?

So I have setup my Aurelia application in the following way and I want to import all my modules and dependencies in Main.js and still be able to inject dependencies in modules like Start.js. I also want to display a splash screen that waits until everything is loaded. Is any of this possible?
main.js
import 'bootstrap';
// TODO: Import all modules here
// import {inject} from "aurelia-framework";
// import {PortalData} from "./portalData";
object export function configure(aurelia){
aurelia.use
.standardConfiguration()
.developmentLogging();
// start aurelia and navigate to app.html / app.js
aurelia.start().then(a=> a.setRoot());
}
app.js
export class App {
// aurelia convention
configureRouter(config, router)
{
this.router = router;
config.map([
{
route:["", "home"],
moduleId:"./start",
title:"SevaLink",
nav:true
}
start.js
import {inject} from "aurelia-framework";
import {PortalData} from "./portalData";
#inject(PortalData)
export class Start {
constructor(portalData){
this.portalData = portalData;
}
activate(){
return this.portalData.getApplications()
.then(apps => this.applications = apps);
}
}
You can import all of your dependencies in any module in your application. I'm not sure what that would accomplish, though. This would just make your application slower to start, and wouldn't really provide any benefit. Aurelia uses lazy loading for modules. If you want to load all of the code for your application at startup, just bundle the application.

Play Framework 2.2 - functional test fails with type mismatch

I've just upgraded to Play 2.2, and since the Helpers have changed, my test isn't compiling anymore.
import org.specs2.mutable.Specification
import play.api.test._
import play.api.test.Helpers._
import play.api.libs.ws._
import play.api.mvc.Results._
class ApplicationSpec extends Specification {
import controllers._
"Application" should {
"test WS logic" in new WithServer {
await(WS.url("http://localhost:3333").get()).status must equalTo(OK)
}
}
}
gives the following compile error
type mismatch;
[error] found : scala.concurrent.Future[play.api.libs.ws.Response]
[error] required: org.specs2.matcher.Matcher[?]
It's just a name clash between play.api.test.Helpers.await and org.specs2.matcher.FutureMatchers.await.
You could just refer to the play helper more explicitly (or rename your import):
Helpers.await(WS.url("http://localhost:3333").get()).status must equalTo(OK)
The following is probably better, however, which hasn't made it into the documentation yet:
https://github.com/playframework/playframework/blob/master/framework/src/play-test/src/main/scala/play/api/test/PlaySpecification.scala
So simply extend PlaySpecification instead of Specification in your test:
import org.specs2.mutable.Specification
import play.api.test._
import play.api.test.Helpers._
import play.api.libs.ws._
import play.api.mvc.Results._
class ApplicationSpec extends PlaySpecification {
import controllers._
"Application" should {
"test WS logic" in new WithServer {
await(WS.url("http://localhost:3333").get()).status must equalTo(OK)
}
}
}