Consider a Service-Bean, that sets a property on some schedule:
@Service
class UserService {
var userInfo: Map<String, UserInfo>? = null
@Scheduled(...)
private fun fetchUserInfo() {
userInfo = callExternalUserEndpoint()
}
}
For testing purposes, I would like to access UserService::userInfo once it has been set by the scheduled function.
My solution so far is to repeatedly call sleep():
@SpringBootTest
class UserServiceTest {
@Autowired
lateinit var userService: UserService
@BeforeEach
fun beforeEach() {
// make sure userInfo not null
while (userService.userInfo == null) {
Thread.sleep(50)
}
}
@Test
fun someTest() {
// access userService.userInfo ...
}
}
I have the feeling, that there is a concept or pattern in Kotlin, that achieves this objective in a standardized and elegant way. From consulting the Kotlin documentation, it seems to me, that one should be able to do this using delegated properties, Delegates.observable() or a combination of the two. However, I have been unable to make it work. A delegated getter for the lateinit variable could look like:
@Component
class Delegate {
@Autowired
lateinit var userService: UserService
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return userService.userInfo.toString()
}
}
Using Delegates.observable() , a variable in the test scope can be defined and its changes monitored. How does one connect the two? Something like Delegates.observable() , but with a custom getter, that accesses userService.userInfo under the hood?
Following Tenfour04's advice, I refactored
UserService, but without using Kotlin coroutines:This way, accessing
userInfoguarantees that a call tofetchUserInfo()has finished before a value is returned, the initialization is encapsulated inUserServiceand an external scope does not have to concern itself with the initialization.