Navneet
03/13/2024, 8:42 AMNavneet
03/13/2024, 7:42 PMNavneet
03/14/2024, 9:23 AMsimon.vergauwen
03/14/2024, 9:56 AMI’d like to run tests treating the entire application as a black box, with external dependencies passed through environment variables, and then conduct tests through API probing. Can anyone provide some insights or clue?If you want to do this, I would opt for dockerising your own application. So launch your application in docker, and test it by sending http request to it. TBH, this wouldn't be my first suggestion 😅 I typically test my modules using
testApplication
, by splitting my main
code like this. https://github.com/nomisRev/ktor-arrow-example/blob/147b8642fbb2f8c351436ff213610b9472153334/src/main/kotlin/io/github/nomisrev/main.kt#L25 From my tests, I am using the production dependencies but with a test configuration meaning that I am connecting to Postgress TestContainers instead of a real one.
This way you can start your server with testApplication
instead of Docker, which is much faster but still get the same guarantees of testing.
Testing SuspendApp specifically is really hard, since you'd be testing a JVM process. It might be possible, but probably really hard and not worth it.
Hope this helps, but I'd be happy to discuss it further ☺️Navneet
03/14/2024, 2:58 PMtestApplication
might not able to capture all run time scenario. Lets take example like this
with(statelessServiceA) {
with(serviceWithStateB()){
with(serviceWithStateC()) {
suspendProcessX()
}
with(serviceWithStateD()) {
suspendProcessY()
}
}
}
“In this case, should there be any hidden dependencies between suspendProcessX
and suspendProcessY
, such scenarios might remain unnoticed since these processes are encapsulated by a service with certain states. ( Or this actual behaviour is independent from suspendApp 🙂 ) Additionally, I’m curious as to why you chose to bundle dependencies rather than using a context
. Was there a specific reason behind this?simon.vergauwen
03/14/2024, 3:21 PMIn this case, should there be any hidden dependencies betweenI'm not entirely sure what you mean, in the example I shared my entire Ktor Application is defined by a single functionandsuspendProcessX
, such scenarios might remain unnoticed since these processes are encapsulated by a service with certain states.suspendProcessY
module
. Which does all Ktor specific things except setup the server
. server
comes from SuspendApp, but it's just embeddedServer
+ wiring the shutdown
function to the ResourceScope
. So, that behaviour is completely independent from SuspendApp.
Additionally, I’m curious as to why you chose to bundle dependencies rather than using aNot sure what you mean by rather than using a. Was there a specific reason behind this?context
context
, if you mean why I don't use CoroutineContext
that's because it's the same as service locator pattern (reflection / runtime errors).
I try to group my dependencies in logical parts, and typically create a graph similar to how you do it in many DI frameworks but without the framework 😅 So I do very basic manually constructing of classes + passing them around. I find it much simpler, and I've compared with many DI frameworks and it typically results in less code.
Most important piece in my DI setup is that I rely on ResourceScope
to make sure all my dependencies are closed correctly when the server shuts down. I've talked about this extensively in two talks if you're interested.
• Talk:
• Demo:
• Here is a talk I gave specifically on the example project I shared before,
Let me know I misunderstood a question, or you have any other questions! ☺️Navneet
03/15/2024, 7:44 AM