https://kotlinlang.org logo
Title
i

igor.wojda

02/27/2023, 1:42 PM
Consider such code:
data class Task(val name: String, val description: String)

class CreateTeskUseCase(val repository: Repository) {
    fun execute(taskRequestModel: TaskRequestModel) {
        val task = Task(taskRequestModel.name, taskRequestModel.description)
        //...
        repository.save(task)
    }
}
This works fine, but when I want to test interaction with the repo the "dummy" factory is required to get testable
Task
instance:
class CreateTeskUseCase(val repository: Repository, val taskFactory: TaskFactory) {
    fun execute(taskRequestModel: TaskRequestModel) {
        val task = taskFactory.create(taskRequestModel.name, taskRequestModel.description)
        //...
        repository.save(task)
    }
}

class TaskFactory {
    fun create(name: String, description: String) = Task(name, description)
}
I wonder if there is a way to generate this
TaskFactory
class (perhaps using
ksp
). Something like this
@GenerateFactory
annotation?
@GenerateFactory
data class Task(val name: String, val description: String)
s

Sam

02/27/2023, 1:43 PM
If
TaskFactory
is a functional interface, you should be able pass
::Task
as the instance. Does that help?
i

igor.wojda

02/27/2023, 1:45 PM
Can you elaborate a bit more on this?
s

Sam

02/27/2023, 1:46 PM
I might be wrong, actually. I was hoping that this would work:
fun interface TaskFactory {
    fun create(name: String, description: String): Task
}

data class Task(val name: String, val description: String)

val factory: TaskFactory = ::Task
But I guess SAM conversion doesn’t work for function references
Oh wait, my syntax was wrong
fun interface TaskFactory {
    fun create(name: String, description: String): Task
}

data class Task(val name: String, val description: String)

val factory = TaskFactory(::Task)
i

igor.wojda

02/27/2023, 4:06 PM
I was thinking about more complete solution that will generate whole factory class/interface code
k

kqr

02/28/2023, 7:26 AM
why do you need factory?
i

igor.wojda

02/28/2023, 8:27 AM
I need factory to test that repo is called with the task (
repository.save(task)
) eg. that
name
String was not accidentally switched with
description
string. How would you test this?
k

kqr

02/28/2023, 12:43 PM
well still, how would factory help this? you just wrapped constructor. you can test constructor separately if that's what you want. in this case, you have request model as input and save method call sideeffect as output. so I would use some argumentcaptor equivalent and verify that method was call via mock/spy
i

igor.wojda

03/02/2023, 8:43 AM
Nice idea @kqr I will give this a try thx
t

Tim Hill

03/02/2023, 6:44 PM
Would something like this do the trick? Depending on how complex the TaskRequestModel is, you might not need to mock that either.
i

igor.wojda

03/02/2023, 9:32 PM
CreateTaskUseCase
serves as a factory, so this basically is the same as initial issue. I am evaluating these
argument captors