mocking a class that depends on firebase in a non-uI test for remote config - kotlin

I have this class that exposes remote configs to others. I thought by creating a class, I would just mock it when testing others that use it but so far, firebase is blocking me. Not sure what I am doing wrong exactly.
class AppRemoteConfig #Inject constructor() {
private var remoteConfig: FirebaseRemoteConfig = Firebase.remoteConfig
private fun setListeningInterval(): Long {
if (BuildConfig.DEBUG){
return 0;
}
return 86400;
}
init {
val configSettings = remoteConfigSettings {
minimumFetchIntervalInSeconds = setListeningInterval()
}
remoteConfig.setConfigSettingsAsync(configSettings)
remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults)
remoteConfig.fetchAndActivate()
.addOnCompleteListener(OnCompleteListener{
if (it.isSuccessful) {
remoteConfig.activate()
}
})
}
fun getString(key: String): String {
return this.remoteConfig.getString(key)
}
}
Now a class uses it this way:
class GetRData #Inject constructor(
private val _remoteConfig: AppRemoteConfig
) {
operator fun invoke(key): String {
try {
return _remoteConfig.getString(key)
} catch(ex: Exception){
return ""
}
return ""
}
}
Now I want to test GetRData class but I get the error: Default FirebaseApp is not initialized in this process null. Make sure to call FirebaseApp.initializeApp(Context) first.
here is what I have tried:
class GetRDataTest {
private var appRemoteConfig = mockk<AppRemoteConfig>(relaxed = true)
private lateinit var getRData : GetRData
#Before
fun setUp(){
getRData = GetRData(appRemoteConfig)
}
#Test
fun `Should get string value`() {
every { appRemoteConfig.getString("status") } returns "red"
val result = getRData.invoke("status")
verify { appRemoteConfig.getString("status") }
Truth.assertThat(result).isEqualTo("red")
}
}

Related

How to mock extensions function in kotlin

I am using Mockk in my project. I am trying to mock my extension function but it cannot find my function. I tried some piece of code but it cannot find the extension function inside my test. Can someone guide me, How can I solve this issue. Thanks
ExploreConsultationsActivity.kt
class ExploreConsultationsActivity : AppCompactActvity () {
... // more function
internal fun setupExploreConsultationVisibility(hasFocus: Boolean) {
if (hasFocus) {
.....
} else if (viewModel.queryText.isEmpty()) {
binding.consultationViewSwitcher.displayConsultationViewSwitcherChild(0)
}
}
internal fun ViewSwitcher.displayConsultationViewSwitcherChild(childNumber: Int) {
visible()
displayedChild = childNumber
}
}
ExploreConsultationsActivityTest.kt
class ExploreConsultationsActivityTest {
#get:Rule
val testInstantTaskExecutorRule: TestRule = InstantTaskExecutorRule()
private val subject by lazy { spyk(ExploreConsultationsActivity()) }
#MockK private lateinit var mockConsultationViewSwitcher: ViewSwitcher
#Before
fun setUp() {
MockKAnnotations.init(this, relaxed = true)
setupMockView()
}
private fun setupMockView() {
mockkStatic(ExploreConsultationsLayoutBinding::class)
every { mockRootView.findViewById<ChipGroup>(R.id.exploreConsultationChips) } returns mockChipGroup
}
#Test
fun `setupExploreConsultationVisibility - `() {
// STUBBING
mockViewModel.queryText = ""
every { mockViewModel.topicSelected } returns ConsultationTopicsArea.ALL
with(mockConsultationViewSwitcher){
any<ViewSwitcher>().displayConsultationViewSwitcherChild(0)
}
// EXECUTION
subject.setupExploreConsultationVisibility(false)
// VERIFICATION
verify {
mockViewModel.filterBy(ConsultationTopicsArea.ALL)
}
}
I am getting this error

Mockk anonymous class

I'm trying to mock anonymous class created in testInstance Sample:
class SomeClass(val someValue:SomeType) :SomeAnotherClass(){
val anonymousClass = object : AnotherClass{
override anotherMethod() { }
}
override fun someMethod(someValue) = anonymousClass.someMethod(someValue)
}
And test class:
class SomeClassTest {
private val someValue: SomeType = mockk()
private val testInstance = spyk(SomeClass(someValue), recordPrivateCalls = true)
#Test
fun `test method`(){
mockkConstructor(CustomTlsSocketFactory::class)
every { anyConstructed<AnotherClass>().someMethod(someValue) } returns mockk()
testInstance.someMethod(someValue)
verify { anyConstructed<AnotherClass>().someMethod(someValue) }
}
}
And for some reason anonymousClass.someMethod(someValue) is trying to call original method not mockk.
Calling testInstance.anonymousClass.isMock is false

how to test project reactor code that does not return a subscription

i'm trying to create a component that stream data from remote service continuously. The component starts and stops according to spring container lifecycle. I'm not sure how to test this component as the subscription is done inside my component so i was wondering wether this is the correct way to implement this kind of component with webflux or not. Does anybody know any similar component in any framework from where i might take some ideas?
Regards
class StreamingTaskAdapter(
private val streamEventsUseCase: StreamEventsUseCase,
private val subscriptionProperties: subscriptionProperties,
) : SmartLifecycle, DisposableBean, BeanNameAware {
private lateinit var disposable: Disposable
private var running: Boolean = false
private var beanName: String = "StreamingTaskAdapter"
private val logger = KotlinLogging.logger {}
override fun start() {
logger.info { "Starting container with name $beanName" }
running = true
doStart()
}
private fun doStart() {
disposable = Mono.just(
CreateSubscriptionCommand(
subscriptionProperties.events,
subscriptionProperties.owningApplication
)
)
.flatMap(streamEventsUseCase::createSubscription)
.flatMap { subscription ->
Mono.just(subscription)
.map(::ConsumeSubscriptionCommand)
.flatMap(streamEventsUseCase::consumeSubscription)
}
.repeat()
.retryWhen(Retry.backoff(MAX_ATTEMPTS, Duration.ofSeconds(2)).jitter(0.75))
.doOnSubscribe { logger.info { "Started event streaming" } }
.doOnTerminate { logger.info { "Stopped event streaming" } }
.subscribe()
}
override fun stop() {
logger.info("Stopping container with name $beanName")
doStop()
}
override fun isRunning(): Boolean = running
private fun doStop() {
running = false
disposable.dispose()
}
override fun destroy() {
logger.info("Destroying container with name $beanName")
doStop()
}
override fun setBeanName(name: String) {
this.beanName = name
}
companion object {
const val MAX_ATTEMPTS: Long = 3
}
}

Testing Soap Consumer. 'uri' must not be empty

I have a method for calling the "marshalSendAndReceive" method on sending a message over Soap.
class SoapConnector : WebServiceGatewaySupport() {
fun getClient(documentId: String): Person {
val request = getSearchRequest(documentId)
val response = webServiceTemplate.marshalSendAndReceive(request) as SearchResponse
return getPerson(response)
}
I also have a configuration file.
#Configuration
class SearchClientConfig {
#Bean
fun marshaller(): Jaxb2Marshaller? {
return Jaxb2Marshaller().apply {
contextPath = "wsdl" //here path to generated java classes from wsdl
}
}
#Bean
fun searchCilent(marshallerJaxb: Jaxb2Marshaller): SoapConnector {
return SoapConnector().apply {
defaultUri = "http://20.40.59.1:8080/cdi/soap/services/ServiceWS"
marshaller = marshallerJaxb
unmarshaller = marshallerJaxb
}
}
}
I want to Mock this method.
#RunWith(SpringRunner::class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#Sql(scripts = ["classpath:db/init.sql"])
#AutoConfigureEmbeddedDatabase(
beanName = "dataSource",
provider = AutoConfigureEmbeddedDatabase.DatabaseProvider.DOCKER
)
class SoapTest : WebServiceGatewaySupport(){
private lateinit var webServiceGatewaySupport: WebServiceGatewaySupport
private lateinit var connector: SoapConnector
#BeforeEach
fun setUp() {
webServiceGatewaySupport = Mockito.mock(WebServiceGatewaySupport::class.java)
}
#Test
fun getClientTest() {
Mockito.`when`(webServiceTemplate.marshalSendAndReceive(ArgumentMatchers.anyObject())).thenReturn(SearchResponse())
connector.getClient(RandomStringUtils.randomAlphabetic(7))
}
}
But there is a bug:
java.lang.IllegalArgumentException: 'uri' must not be empty
I don't understand what the problem is and I don't know how to make a working Mock of this method.

Kotlin - Don't run unit test until lateinit property is initialized

I have a case where the unit of code I'm testing is running on a different thread and so the test executes and fails before the unit has finished executing:
class Tests {
private lateinit var result: String
#BeforeAll
fun setup() {
DataService().subscribe {
result = it
}
}
#Test
fun `get result from data service`() {
assert(result.contains("Hello"))
}
}
When the test runs, I get the following exception:
kotlin.UninitializedPropertyAccessException: lateinit property result has not been initialized
How can I ensure that the tests don't run before result has been initialized?
The test in the provided form won't work: #BeforeAll is allowed only on static methods, but then it couldn't access the result field. It can be solved by using #BeforeEach and #TestInstance(TestInstance.Lifecycle.PER_METHOD) [but see the UPDATE at the end of the post]
Regarding the result initialization itself: you can check if it has been initialized using this::result.isInitialized, e.g.:
#TestInstance(TestInstance.Lifecycle.PER_METHOD)
class AwaitTest {
private lateinit var result: String
#BeforeEach
fun setup() {
DataService().subscribe {
result = it
}
}
#Test
fun `get result from data service`() = runBlocking {
awaitInitialization()
assert(result.contains("Hello"))
}
suspend fun awaitInitialization() {
while(!this::result.isInitialized) {
delay(100)
}
}
}
Alternatively you could use awaitility:
#TestInstance(TestInstance.Lifecycle.PER_METHOD)
class AwaitTest {
private lateinit var result: String
#BeforeEach
fun setup() {
DataService().subscribe {
result = it
}
}
#Test
fun `get result from data service`() {
await until { this#AwaitTest::result.isInitialized }
assert(result.contains("Hello"))
}
}
Or even better, move await to the setup() method:
#TestInstance(TestInstance.Lifecycle.PER_METHOD)
class AwaitTest {
private lateinit var result: String
#BeforeEach
fun setup() {
DataService().subscribe {
result = it
}
await until { this#AwaitTest::result.isInitialized }
}
#Test
fun `get result from data service`() {
assert(result.contains("Hello"))
}
}
UPDATE:
Actually a #BeforeAll method doesn't need to be static if the test class is annotated with the#TestInstance(TestInstance.Lifecycle.PER_CLASS):
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
class AwaitTest {
private lateinit var result: String
#BeforeAll
fun setup() {
DataService().subscribe {
result = it
}
await until { this#AwaitTest::result.isInitialized }
}
#Test
fun `get result from data service`() {
assert(result.contains("Hello"))
}
}