Ivan Lorenz
11/23/2021, 4:57 PMfun RedisConnection.saveRedisSession(session: Session): Save<Unit> How can we achieve that? I understand that this is a impossible approach because extension functions are resolved statically. Then, how to mock o test double them? Or the real problem is we should not need to mock functions used by other functions? Then what to test? 😄 Sorry for the mess but switching paradigms is a tough brain task. Thank you very much in advance.pakoito
11/23/2021, 5:02 PMpakoito
11/23/2021, 5:02 PMpakoito
11/23/2021, 5:02 PMpakoito
11/23/2021, 5:03 PMpakoito
11/23/2021, 5:03 PMpakoito
11/23/2021, 5:03 PMpakoito
11/23/2021, 5:03 PMpakoito
11/23/2021, 5:04 PMpakoito
11/23/2021, 5:04 PMpakoito
11/23/2021, 5:04 PMpakoito
11/23/2021, 5:04 PMpakoito
11/23/2021, 5:05 PMfun IService.doThing(s: UserState) =
HardDependency.mangleUser(this.stuff(s))pakoito
11/23/2021, 5:05 PMpakoito
11/23/2021, 5:06 PMfun IService.doThingIface(soft: IHardDep, u: UserState) =
soft.mangleUser(stuff(u))
or
fun IService.doThingLambda(
s: UserState,
f: (UserState) -> UserState) =
f(stuff(s))pakoito
11/23/2021, 5:07 PMpakoito
11/23/2021, 5:09 PMobject TestService: IService {
override fun stuff(user: UserState): UserState =
user.apply { name = "hello" }
}
...
val result = TestService.doThingLambda(someState) { user->
user.apply { name = name.toUpper() }
}
expect(result.name).toEqual("HELLO")pakoito
11/23/2021, 5:13 PMpakoito
11/23/2021, 5:14 PMIvan Lorenz
11/23/2021, 5:15 PMimplicit dependencies as receivers because you switch style to inject them as function parameters. Is that correct?pakoito
11/23/2021, 5:17 PMpakoito
11/23/2021, 5:18 PMpakoito
11/23/2021, 5:18 PMpakoito
11/23/2021, 5:18 PMpakoito
11/23/2021, 5:18 PMpakoito
11/23/2021, 5:19 PMpakoito
11/23/2021, 5:19 PMpakoito
11/23/2021, 5:19 PMpakoito
11/23/2021, 5:20 PMfun bla(/* 20 parameters */) refactors to fun bla(a: IFace1 /* 5 parameters */, b: IFace2 /* 4 parameters */...) etcIvan Lorenz
11/23/2021, 5:20 PMsuspend fun Dependencies.loadNetworkSpeakers(): List<Speaker> =
speakerService.loadSpeakers() // access dependencies
suspend fun Dependencies.loadNetworkTalks(speakerIds: List<SpeakerId>): List<Talk> =
talkService.loadTalks(speakerIds) // access dependencies
suspend fun Dependencies.persistTalks(talks: List<Talk>): List<Talk> =
talkDatabase.persistTalks(talks) // access dependencies
abstract class Dependencies {
val speakerService: SpeakerServiceOps by lazy { SpeakerService() }
val talkService: TalkServiceOps by lazy { TalkService() }
val talkDatabase: TalkDatabaseOps by lazy { TalkDatabase() }
}
As you can see, you have at hand all the dependencies in an extfun.pakoito
11/23/2021, 5:21 PMpakoito
11/23/2021, 5:21 PMIvan Lorenz
11/23/2021, 5:22 PMDependencies.persistTalks(talks: List<Talk>): List<Talk> ?pakoito
11/23/2021, 5:22 PMpakoito
11/23/2021, 5:24 PMfun Dependencies.doThing(talks: List<Talk>) =
improveTalks(talks)
.let(::persistTalks)
.let(::logTalks)pakoito
11/23/2021, 5:24 PMpakoito
11/23/2021, 5:25 PMfun Dependencies.doThing(talks: List<Talk>, persist: (List<Talk>) -> List<Talk>, log: (List<Talk>) -> List<Talk>) =
improveTalks(talks)
.let(::persist)
.let(::log)pakoito
11/23/2021, 5:25 PMpakoito
11/23/2021, 5:25 PMIvan Lorenz
11/23/2021, 5:26 PMpakoito
11/23/2021, 5:26 PMinterface TalkActions {
fun persist(l: List<Talk>): List<Talk>
fun log(l: List<Talk>): List<Talk>
}pakoito
11/23/2021, 5:26 PMIvan Lorenz
11/23/2021, 5:27 PMpakoito
11/23/2021, 5:27 PMfun Dependencies.doThing(talks: List<Talk>, actions: TalkActions) =
improveTalks(talks)
.let(actions::persist)
.let(actions::log)pakoito
11/23/2021, 5:27 PMfun TalkActions.doThing(talks: List<Talk>, d: Dependencies) =
d.improveTalks(talks)
.let(::persist)
.let(::log)pakoito
11/23/2021, 5:27 PMpakoito
11/23/2021, 5:27 PM