Error while accessing references from Resource.kt file in Kotlin project - kotlin

I get below error while trying to access refferences from my Resources.kt file
.
Below shows my full code on LoginViewModel.kt
package lk.ac.kln.mit.stu.mobileapplicationdevelopment.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.bumptech.glide.load.engine.Resource
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.FirebaseUser
import com.google.firebase.firestore.auth.User
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
#HiltViewModel
class LoginViewModel #Inject constructor(
private val firebaseAuth: FirebaseAuth
): ViewModel() {
private val _login = MutableSharedFlow<Resource<FirebaseUser>>()
// MutableSharedFlow<Resource<FirebaseUser>>()
val login = _login.asSharedFlow()
fun login(email: String, password: String){
viewModelScope.launch {
_login.emit(Resource.Loading())
}
firebaseAuth.signInWithEmailAndPassword(
email,password
).addOnSuccessListener {
viewModelScope.launch {
it.user?.let {
_login.emit(Resource.Success(it))
}
}
}.addOnFailureListener {
viewModelScope.launch {
_login.emit(Resource.Error(it.message.toString()))
}
}
}
}
Below shows the Resource.kt file
package lk.ac.kln.mit.stu.mobileapplicationdevelopment.util
sealed class Resource<T>(
val data: T? = null,
val message: String? = null
){
class Success<T>(data:T):Resource<T>(data)
class Error<T>(message:String):Resource<T>(message = message)
class Loading <T>: Resource<T>()
class Unspecified <T>: Resource<T>()
}
I have tried to implement using the same way I did for other view models.
I did the same approach to access same variables on RegisterViewModel.kt and it works without any error. Below is the code for that functioning view model
package lk.ac.kln.mit.stu.mobileapplicationdevelopment.viewmodel
import androidx.lifecycle.ViewModel
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.FirebaseUser
import com.google.firebase.firestore.FirebaseFirestore
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.runBlocking
import lk.ac.kln.mit.stu.mobileapplicationdevelopment.data.User
import lk.ac.kln.mit.stu.mobileapplicationdevelopment.util.*
import lk.ac.kln.mit.stu.mobileapplicationdevelopment.util.Constants.USER_COLLECTION
import javax.inject.Inject
#HiltViewModel
class RegisterViewModel #Inject constructor(
private val firebaseAuth : FirebaseAuth,
private val db: FirebaseFirestore
) : ViewModel() {
private val _register = MutableStateFlow<Resource<User>>(Resource.Unspecified())
val register : Flow<Resource<User>> = _register
private val _validation = Channel<RegisterFieldsState>()
val validation =_validation.receiveAsFlow()
fun createAccountWithEmailAndPassword(user: User, password: String) {
if (checkValidation(user, password)){
runBlocking {
_register.emit(Resource.Loading())
}
firebaseAuth.createUserWithEmailAndPassword(user.email, password)
.addOnSuccessListener {
it.user?.let {
saveUserInfo(it.uid, user)
// _register.value = Resource.Success(it)
}
}
.addOnFailureListener {
_register.value = Resource.Error(it.message.toString())
}
} else
{
val registerFieldsState = RegisterFieldsState(
validateEmail(user.email), validatePassword(password)
)
runBlocking {
_validation.send(registerFieldsState)
}
}
}
private fun saveUserInfo(userUid: String, user: User) {
db.collection(USER_COLLECTION)
.document(userUid)
.set(user)
.addOnSuccessListener {
_register.value = Resource.Success(user)
}
.addOnFailureListener {
_register.value = Resource.Error(it.message.toString())
}
}
private fun checkValidation(
user: User,
password: String
) : Boolean {
val emailValidation = validateEmail(user.email)
val passwordValidation = validatePassword(password)
val shouldRegister =
emailValidation is RegisterValidation.Success && passwordValidation is RegisterValidation.Success
return shouldRegister
}
}
Can someone help me with solving above issue please.Why it gives an error when trying to call Resource.Loading() from LoginViewModel.kt?

Please check import class in LoginViewModel, You are importing
import com.bumptech.glide.load.engine.Resource
It should be from this package lk.ac.kln.mit.stu.mobileapplicationdevelopment.util

Related

TransactionalEventListener not invoked in #MicronautTest

Problem description
While system end-to-end tests are invoking methods annotated with #TransactionalEventListener, I'm not able to invoke the same methods in narrower tests annotated with #MicronautTest.
I've tested numerous variants with both injected EntityManager and SessionFactory. #MicronautTest(transactional = false) is also tested. Calling JPA-method inside TestSvcWithTxMethod#someMethod is also tested with same result. I've also tried tests without mocking TestAppEventListener.
The below test/code yields
Verification failed: call 1 of 1:
TestAppEventListener(#1).beforeCommit(any())) was not called.
java.lang.AssertionError: Verification failed: call 1 of 1:
TestAppEventListener(#1).beforeCommit(any())) was not called.
Calls to same mock: 1) TestAppEventListener(#1).hashCode()
Environment: Micronaut 3.7.5, Micronaut Data 3.9.3
Minimal reproducible code
Test is failing as well with transactional = false
import io.kotest.core.spec.style.BehaviorSpec
import io.micronaut.test.annotation.MockBean
import io.micronaut.test.extensions.kotest5.MicronautKotest5Extension.getMock
import io.micronaut.test.extensions.kotest5.annotation.MicronautTest
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import no.mycompany.myapp.eventstore.services.appeventpublisher.testinfra.DefaultTestAppEventListener
import no.mycompany.myapp.eventstore.services.appeventpublisher.testinfra.TestAppEventListener
import no.mycompany.myapp.eventstore.services.appeventpublisher.testinfra.TestSvcWrapper
#MicronautTest
class AppEventWithBeforeCommitListenerMockTest(
testSvcWrapper: TestSvcWrapper,
testAppEventListener: TestAppEventListener
) : BehaviorSpec({
given("context with app event listener") {
`when`("calling someMethod") {
val mockBeforeCommitTestListener = getMock(testAppEventListener)
every { mockBeforeCommitTestListener.beforeCommit(any()) } answers {}
every { mockBeforeCommitTestListener.afterRollback(any()) } answers {}
testSvcWrapper.someMethod(message = "call #1")
verify { mockBeforeCommitTestListener.beforeCommit(any()) }
}
}
}) {
#MockBean(DefaultTestAppEventListener::class)
fun mockTestAppEventListener(): TestAppEventListener = mockk()
}
TestSvcWrapper
import jakarta.inject.Singleton
#Singleton
class TestSvcWrapper(
private val testSvcWithTxMethod: TestSvcWithTxMethod
) {
fun someMethod(message: String) {
testSvcWithTxMethod.someMethod(message)
}
}
TestSvcWithTxMethod
import io.micronaut.context.event.ApplicationEventPublisher
import jakarta.inject.Singleton
import javax.transaction.Transactional
#Singleton
open class TestSvcWithTxMethod(
private val eventPublisher: ApplicationEventPublisher<TestEvent>
) {
#Transactional(Transactional.TxType.REQUIRES_NEW)
open fun someMethod(message: String) {
eventPublisher.publishEvent(TestEvent(message))
}
}
TestEvent
import io.micronaut.core.annotation.Introspected
#Introspected
data class TestEvent(val message: String)
TestAppEventListener
interface TestAppEventListener {
fun beforeCommit(event: TestEvent)
fun afterRollback(event: TestEvent)
}
DefaultTestAppEventListener
import io.micronaut.transaction.annotation.TransactionalEventListener
import jakarta.inject.Singleton
import java.util.concurrent.atomic.AtomicInteger
#Singleton
open class DefaultTestAppEventListener : TestAppEventListener {
val receiveCount = AtomicInteger()
#TransactionalEventListener(TransactionalEventListener.TransactionPhase.BEFORE_COMMIT)
override fun beforeCommit(event: TestEvent) {
receiveCount.getAndIncrement()
}
#TransactionalEventListener(TransactionalEventListener.TransactionPhase.AFTER_ROLLBACK)
override fun afterRollback(event: TestEvent) {
receiveCount.getAndIncrement()
}
}
The answer was found in the micronaut-test repo. Key is to inject SynchronousTransactionManager<Any>, create and then commit/rollback transaction.
I was not able to make mock-test from question pass, most likely because of the annotations, but the following tests are working. I made some modifications to the types in question, hence I added code for the new implementations below.
import io.kotest.core.spec.style.BehaviorSpec
import io.kotest.matchers.shouldBe
import io.micronaut.test.extensions.kotest5.annotation.MicronautTest
import io.micronaut.transaction.SynchronousTransactionManager
import io.micronaut.transaction.support.DefaultTransactionDefinition
import no.mycompany.myapp.eventstore.services.appeventpublisher.testinfra.TestAppEventListener
import no.mycompany.myapp.eventstore.services.appeventpublisher.testinfra.TestSvcWithTxMethod
#MicronautTest(transactional = false)
class AppEventWithBeforeCommitListenerTest(
testSvcWithTxMethod: TestSvcWithTxMethod,
testAppEventListener: TestAppEventListener,
transactionManager: SynchronousTransactionManager<Any>
) : BehaviorSpec({
given("context with app event listener") {
`when`("calling someMethod with commit") {
val tx = transactionManager.getTransaction(DefaultTransactionDefinition())
testSvcWithTxMethod.someMethod(message = "call #1")
transactionManager.commit(tx)
then("TestAppEventListener should have received message") {
testAppEventListener.beforeCommitReceiveCount.get() shouldBe 1
}
}
`when`("calling someMethod with rollback") {
val tx = transactionManager.getTransaction(DefaultTransactionDefinition())
testSvcWithTxMethod.someMethod(message = "call #2")
transactionManager.rollback(tx)
then("TestAppEventListener should have received message") {
testAppEventListener.afterRollbackReceiveCount.get() shouldBe 1
}
}
}
})
TestSvcWithTxMethod
import io.micronaut.context.event.ApplicationEventPublisher
import jakarta.inject.Singleton
import javax.transaction.Transactional
#Singleton
open class TestSvcWithTxMethod(
private val eventPublisher: ApplicationEventPublisher<TestEvent>
) {
#Transactional
open fun someMethod(message: String) {
eventPublisher.publishEvent(TestEvent(message))
}
}
TestAppEventListener
import io.micronaut.transaction.annotation.TransactionalEventListener
import jakarta.inject.Singleton
import java.util.concurrent.atomic.AtomicInteger
#Singleton
open class TestAppEventListener {
val beforeCommitReceiveCount = AtomicInteger()
val afterRollbackReceiveCount = AtomicInteger()
#TransactionalEventListener(TransactionalEventListener.TransactionPhase.BEFORE_COMMIT)
open fun beforeCommit(event: TestEvent) {
beforeCommitReceiveCount.getAndIncrement()
}
#TransactionalEventListener(TransactionalEventListener.TransactionPhase.AFTER_ROLLBACK)
open fun afterRollback(event: TestEvent) {
afterRollbackReceiveCount.getAndIncrement()
}
}
TestEvent (unchanged)
import io.micronaut.core.annotation.Introspected
#Introspected
data class TestEvent(val message: String)

kotlin testing error cannot create parent directories

When I run test, I am getting the error when I try to test if Datastore.edit had been called:
java.io.IOException: Unable to create parent directories of /data/user/0/com.example.app.test/files/datastore/user.preferences_pb
It is a small class that handles Datastore, which is the following:
Pref.kt
class Pref {
companion object {
#Volatile
private var INSTANCE: Pref? = null
private var dataStore: DataStore<Preferences>? = null
fun getInstance(context: Context): Pref? {
if (INSTANCE == null) {
synchronized(Pref::class) {
INSTANCE = Pref()
dataStore = context.createDataStore("user")
}
}
return INSTANCE
}
}
suspend fun save(key: String, value: String) {
val dataStoreKey = preferencesKey<String>(key)
dataStore?.edit { settings ->
settings[dataStoreKey] = value
}
}
}
PrefTest.kt
import android.content.Context
import android.provider.ContactsContract
import android.util.Log
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.datastore.core.DataStore
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert.*
import org.junit.Rule
import org.junit.runner.RunWith
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.preferencesKey
import androidx.test.platform.app.InstrumentationRegistry
import io.mockk.*
import io.mockk.MockKAnnotations.init
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
#RunWith(AndroidJUnit4::class)
class PrefTest {
private val context : Context = InstrumentationRegistry.getInstrumentation().context
#get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
private val mockDataStore = mockk<DataStore<Preferences>>()
#Before
fun setup() {
init(this, relaxed = true)
}
#Test
fun saveValue() = runBlocking {
val dataStoreKey = preferencesKey<String>(storeKey)
Pref.getInstance(context)?.save("key", "value")
coVerify { mockDataStore.edit {
dataStoreKey
} }
}
}
in my device, I can see the directory /data/user/0/com.example.app.test/files. But not sure why the datastore directories couldn't be created for it to continue testing.

Display asset text file in Composable function using Kotlin Jetpack Compose

I'm trying to read a text file using Kotlin from my Assets folder and display it to a Compose text widget. Android Studio Arctic Fox 2020.3
The following code runs successfully and displays the text file to the Output console, however I can't figure out how to get the text file and pass it to a Compose text widget.
You'll notice that I have 2 text() calls inside ReadDataFile(). The first text() is outside of try{} and it works fine, but the text() inside the try{} causes an error: "Try catch is not supported around composable function invocations"
How can I make this work?
Thanks!
package com.learning.kotlinreadfile
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import com.learning.kotlinreadfile.ui.theme.KotlinReadFileTheme
import java.io.InputStream
import java.io.IOException
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
KotlinReadFileTheme {
// A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colors.background) {
ReadDataFile()
}
}
}
}
}
#Composable
fun ReadDataFile() {
println("Read Data File")
Text("Read Data File")
val context = LocalContext.current
try {
val inputStream: InputStream = context.assets.open("data.txt")
val size: Int = inputStream.available()
val buffer = ByteArray(size)
inputStream.read(buffer)
var string = String(buffer)
println(string)
//Text(string) // ERROR: Try catch is not supported around composable function invocations
} catch (e: IOException) {
e.printStackTrace()
println("Error")
}
}
Caution
File read (I/O) operations can be long, so it is not recommended to use the UI scope to read files. But that's not what's causing the problem, I'm just warning you that if it reads very large files, it can make your app crash because it does a very long processing in the UI thread. I recommend checking this link if you're not familiar with this type of problem.
Problem solving following best practices
Fortunately Jetpack compose works very well with reactive programming, so we can take advantage of that to write reactive code that doesn't face the aforementioned problems.
I made an example very similar to yours, I hope you can understand:
UiState file
As stated earlier, reading a file can be a long process, so let's imagine 3 possible states, "loading", "message successful" and "error". In the case of "successful message" we will have a possibly null string that will no longer be null when the message is actually read from the txt file:
package com.example.kotlinreadfile
data class UiState(
val isLoading: Boolean,
val isOnError: Boolean,
val fileMessage: String?
)
MainActivity.kt file
Here will be just our implementation of the UI, in your case the text messages arranged in the application. As soon as we want to read these messages on the screen we will make a request to our ViewModel:
package com.example.kotlinreadfile
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.layout.*
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import com.example.kotlinreadfile.ui.theme.KotlinReadFileTheme
class MainActivity : ComponentActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
KotlinReadFileTheme {
// A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colors.background) {
val context = LocalContext.current
viewModel.loadData(context)
ScreenContent(viewModel.uiState.value)
}
}
}
}
#Composable
fun ScreenContent(uiState: UiState) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(text = "Read Data File")
Spacer(modifier = Modifier.height(8.dp))
when {
uiState.isLoading -> CircularProgressIndicator()
uiState.isOnError -> Text(text = "Error when try load data from txt file")
else -> Text(text = "${uiState.fileMessage}")
}
}
}
}
MainViewModel.kt file
If you are unfamiliar with the ViewModel class I recommend this official documentation link.
Here we will focus on "our business rule", what we will actually do to get the data. Since we are dealing with an input/output (I/O) operation we will do this in an appropriate scope using viewModelScope.launch(Dispatchers.IO):
package com.example.kotlinreadfile
import android.content.Context
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.IOException
import java.io.InputStream
class MainViewModel : ViewModel() {
private val _uiState = mutableStateOf(
UiState(
isLoading = true,
isOnError = false,
fileMessage = null
)
)
val uiState: State<UiState> = _uiState
fun loadData(context: Context) {
viewModelScope.launch(Dispatchers.IO) {
try {
val inputStream: InputStream = context.assets.open("data.txt")
val size: Int = inputStream.available()
val buffer = ByteArray(size)
inputStream.read(buffer)
val string = String(buffer)
launch(Dispatchers.Main) {
_uiState.value = uiState.value.copy(
isLoading = false,
isOnError = false,
fileMessage = string
)
}
} catch (e: IOException) {
e.printStackTrace()
launch(Dispatchers.Main) {
_uiState.value = uiState.value.copy(
isLoading = false,
isOnError = true,
fileMessage = null
)
}
}
}
}
}
jetpack compose by state refresh, please try
#Preview
#Composable
fun ReadDataFile() {
var dataText by remember {
mutableStateOf("asd")
}
println("Read Data File")
Column {
Text("Read Data File")
Text(dataText)
}
val context = LocalContext.current
LaunchedEffect(true) {
kotlin.runCatching {
val inputStream: InputStream = context.assets.open("data.txt")
val size: Int = inputStream.available()
val buffer = ByteArray(size)
inputStream.read(buffer)
String(buffer)
}.onSuccess {
it.logE()
dataText = it
}.onFailure {
dataText = "error"
}
}
}

Add markers to a map with Firebase

I want to make an application with Kotlin and Google Maps in which the user can add markers on the Google Map and that these markers are sent to Firebase and other users can see those same markers on the map.
This is what I have done but it is not working well for me.
package com.racrapa.displayinglocationapp
import android.content.ContentValues
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.annotation.NonNull
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.MarkerOptions
import com.google.firebase.database.*
import com.google.firebase.database.ktx.database
import com.google.firebase.ktx.Firebase
import com.google.firebase.database.ValueEventListener
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.DatabaseReference
private const val TAG = "MapsActivity"
class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var mMap: GoogleMap
public lateinit var databaseRef: DatabaseReference
private lateinit var database: DatabaseReference
private var markers: MutableList<Marker> = mutableListOf()
private var postListener: ValueEventListener? = null
var mDatabase: DatabaseReference? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
databaseRef = Firebase.database.reference
mDatabase = FirebaseDatabase.getInstance().reference.child("userlocation")
database = Firebase.database.reference
}
This is to get the data from Firebase
public override fun onStart() {
super.onStart()
var postListener: ValueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
val locationlogging = dataSnapshot.child("userlocation").getValue(LocationLogging::class.java)
var driverLat=locationlogging?.Latitude
var driverLong=locationlogging?.Longitude
if (driverLat != null && driverLong != null) {
val driverLoc = LatLng(driverLat, driverLong)
val markerOptions = MarkerOptions().position(driverLoc).title("Driver")
mMap.addMarker(markerOptions)
Toast.makeText(applicationContext, "Locations accessed from the database", Toast.LENGTH_LONG).show()
}
}
}
override fun onCancelled(error: DatabaseError) {}
}
databaseRef.addValueEventListener(postListener)
}
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
mMap.setOnMapLongClickListener { latLng ->
Log.i(TAG, "onMapLongClickListener")
setMapLongClick(latLng)
}
}
This is the function of sending coordinates to Firebase
private fun setMapLongClick(latLng: LatLng) {
if (latLng != null) {
Log.e("Latitude: ", latLng.latitude.toString() + "longitude: " + latLng.longitude)
val latlang: MutableMap<String, Double> = HashMap()
latlang["latitude"] = latLng.latitude
latlang["longitude"] = latLng.longitude
mDatabase!!.child("userlocation").push().setValue(latlang)
onStart()
}
}
}

Kotlin Micronaut Mockk no answer found exception

I am new to the Micronaut framework and trying to test a demo example I created.
I am encountering the error io.mockk.MockKException: no answer found for: MathFacade(#3).computeAgain(3).
My code works as such - MathService invokes MathFacade. I want to test MathService so I mock MathFacade in my MathServiceTest with intentions to only test MathService.
My code is as below:
MathServiceTest
package io.micronaut.test.kotlintest
import io.kotlintest.specs.BehaviorSpec
import io.micronaut.test.annotation.MicronautTest
import io.micronaut.test.annotation.MockBean
import io.micronaut.test.extensions.kotlintest.MicronautKotlinTestExtension.getMock
import io.mockk.mockk
import io.mockk.every
import io.reactivex.Single
import kotlin.math.pow
import kotlin.math.roundToInt
#MicronautTest
class MathServiceTest(
private val mathService: MathService,
private val mathFacade: MathFacade
): BehaviorSpec({
given("the math service") {
`when`("the service is called with 3") {
val mock = getMock(mathFacade)
every { mock.computeAgain(any()) } answers {
Single.just(firstArg<Int>().toDouble().pow(3).roundToInt())
}
val result = mathService.compute(2)
then("the result is 9") {
mathService.compute(3).test().assertResult(27)
}
}
}
}) {
#MockBean(MathFacade::class)
fun mathFacade(): MathFacade {
return mockk()
}
}
MathService
package io.micronaut.test.kotlintest
import io.reactivex.Single
import javax.inject.Singleton
#Singleton
class MathService(private val mathFacade: MathFacade) {
fun compute(num: Int): Single<Int> {
return mathFacade.computeAgain(num)
}
}
MathFacade
package io.micronaut.test.kotlintest
import io.reactivex.Single
import javax.inject.Singleton
#Singleton
class MathFacade() {
fun computeAgain(num: Int): Single<Int>{
return Single.just(num*4)
}
}
Any help will be appreciated!