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