https://kotlinlang.org logo
Title
g

Goetz Markgraf

02/02/2023, 10:01 AM
Hello. I have a ktor route that calls a simple business function to process data. The Route is responsible for receiving data from the body and passing it to the business function, and for formatting the returned values. Like so:
get("/some/uri") {
  val data = call.receive<SomeType>()
  val result = doBusinessStuffWith(data)
  call.respond(result.doSomeFormatting()
}
And the business function is defined somewhere else:
fun doBusinessStuffWith(data: SomeType): SomeReturnType {
...
}
Is there a way to test the controller in isolation by mocking the business function
doBusinessStuffWith
? In Javascript, you can mock any function call with
jest
. I assume, it is not that easy in kotlin, but is there a nice way? Thank you for your ideas …
d

dave

02/02/2023, 10:04 AM
You can, of course use a mock. Suggest that you maybe think about structuring your app using Hexagonal Architecture to split your adapter logic from your business logic.
s

Sam

02/02/2023, 10:04 AM
You can indeed mock top level functions with something like #mockk. I don’t find mocking top level functions in Kotlin quite as clean as jest, but it’s not bad. The downside is it stops you from running tests in parallel.
d

Dominik Sandjaja

02/02/2023, 10:04 AM
I propose to move the
doBusinessStuffWith(...)
to a dedicated class. This would not only make testing simpler (you can then simply mock that class and the method call), but it would also clarify the responsibilities of the two classes: One for routing and request/response handling, one for doing logic.
g

Goetz Markgraf

02/02/2023, 10:07 AM
@Dominik Sandjaja That’s how you would do it with spring boot. What I like at ktor is that you don’t have to write classes but can work functional. The separation can come from different files that use private and public funtions but no classes. @Sam That sound interesting. I will try that, thank you. @dave Could be an interesting approach. But I always find the “stiching together” tiresome and data has to flow up- and downward longer ways.
Some thought that I had: Can you use Koin to inject a function? That could solve the problem and be still quite functional. I want to use Koin in the backend anyway, but am pretty new to that framework
d

Dominik Sandjaja

02/02/2023, 10:09 AM
We use Koin and we use a hexagonal approach, exactly to split the responsibilities: Input/Output into a system is e.g. the HTTP route, the actual business logic is in a separate class. Yes, it would be the same in Spring, but that does not necessarily mean that it's a bad thing 🙂
d

dave

02/02/2023, 10:09 AM
If you don't use a DI framework, you could inject a function into your controller. Probably doesn't work with the magic though 😂
g

Goetz Markgraf

02/02/2023, 10:10 AM
Thank you all. I will take a look.
d

dave

02/02/2023, 10:10 AM
fun myController(fn: (String) -> DomainThing)