Trying to convert this Mockito test to Mockk results in error - android

Having issues with the following conversion from Mockito to Mockk.
So I have this
#Mock
private lateinit var loginLiveDataObserver: Observer<LoginResult>
val inOrder = inOrder(loginLiveDataObserver)
inOrder.verify(loginLiveDataObserver).onChanged(enableLoading)
inOrder.verify(loginLiveDataObserver).onChanged(loginResults)
inOrder.verify(loginLiveDataObserver).onChanged(disableLoading)
Try turning it into this
private val loginLiveDataObserver = mockk<Observer<LoginResult>>()
verifyOrder {
loginLiveDataObserver.onChanged(enableLoading)
loginLiveDataObserver.onChanged(loginResults)
loginLiveDataObserver.onChanged(disableLoading)
}
Gives me the following error
io.mockk.MockKException: no answer found for: Observer(#4).onChanged(Loading(value=true))

Your exception says it all (and one of the direct answers), you always have to specify the behaviour of your mocks..
in your case:
private val loginLiveDataObserver = mockk<Observer<LoginResult>>()
// Example answer you can use different here
every { loginLiveDataObserver.onChange(any()) } answers nothing
verifyOrder {
loginLiveDataObserver.onChanged(enableLoading)
loginLiveDataObserver.onChanged(loginResults)
loginLiveDataObserver.onChanged(disableLoading)
}
Check the Documentation at this point and look for the every { ... } part in the example
hope this helps.

Related

Method isDigitsOnly in android.text.TextUtils not mocked Error

I created a validation use case in which I'm validating the input using isDigitsOnly that use TextUtils internally.
override fun isDigitsOnly(size: String): Boolean {
return !size.trim().isDigitsOnly()
}
when I tried to test it, I got this error
Method isDigitsOnly in android.text.TextUtils not mocked
Does anyone know how I can mock the textUtils in my test class
#RunWith(MockitoJUnitRunner::class)
class ValidationInputImplTest {
#Mock
private lateinit var mMockTextUtils: TextUtils
private lateinit var validationInputImpl: ValidationInputImpl
#Before
fun setUp() {
validationInputImpl = ValidationInputImpl()
}
#Test
fun `contains only digits, returns success`() {
val input = "66"
val result = validationInputImpl(input)
assertTrue(result is ValidationResult.Success)
}
}
At the time of writing the answer,you cannot do that. Because the android code ,that you see is not actual code. You cannot create unit test for that. The default implementation of the methods in android.jar is to throw exception.
One thing you can do is, adding the below in build.gradle file.
But it make the android classes not to throw exception. But it will always return default value. So the test result may actually not work. It is strictly not recommended.
android {
testOptions {
unitTests.returnDefaultValues = true
}
}
The better way to do copy the code from android source and paste the file under src/test/java folder with package name as android.text .
Link to Answer

mockk a global property in kotlin

I am facing the same issue as asked in the below question. please help me out.
Mock a "global" property in Kotlin
I tried solution provided in above question but nothing is working. and I am asking the same question because I am not able to post any comment on the previous question.
I am trying to write test case for below class
class CustomLogger constructor(val ctx: Context, embEnabled: Boolean = false) : Logger {
private val loggers = arrayListOf<Logger>()
fun get() = loggers
init {
if (embEnabled)
loggers.add(Emb(ctx))
if (BuildConfig.DEBUG)
loggers.add(DebugLogger(ctx))
}
override fun logError(t: Throwable, msg: String?) {
loggers.forEach { logger ->
logger.logError(t, msg)
}
}
}
enter code here
Here I am trying to mock get() or init{}
that was on dam question but i got you
note this can only be used in unittest as mockito static mock is not support on Android JVM
testImplementation "org.mockito:mockito-inline:4.8.1" you gonna need
this so added
Update you need to call this i forgot to add it sorry in your test case before call the method
Mockito.mockStatic(Class.forName("com.udacity.project4.locationreminders.RemindersActivityKt"))
fun getMockForMethod(clazz: Class<*>, methodName: String, methodResponse: Any) {
val method: Method = clazz.getMethod(methodName)
Mockito.`when`(method.invoke(null)).thenReturn(methodResponse)
}
now i created the method to handle no argument methods you can modifiy it as you see fit just pass the class using it name
getMockForMethod(Class.forName("com.udacity.project4.locationreminders.RemindersActivityKt"),
"doSomething","New Response")
Assert.assertEquals("New Response", doSomething())
works like a charm Enjoy 😁
i have updated the above code for anyone to use with static members in kotlin
your updates makes this easy to do now it is a class that you can mock entirly and easliy mock any methods
val loggerMock= Mockito.mock(Logger::class.java)
Mockito.`when`(loggerMock.loggers).thenReturn(new array of loggers)

Getting error MockKException: no answer found for: Observer(#8).onChanged Android

I'm writing a unit test. Below is my code. The architecture is MVVM using Dagger2. I'm calling the login function residing in the LoginViewModel, which is notifying the getLoginState function. The error I'm getting is:
Error:
io.mockk.MockKException: no answer found for: Observer(#8).onChanged(Success(data=))
at io.mockk.impl.stub.MockKStub.defaultAnswer(MockKStub.kt:90)
LoginViewModelClass:
fun logIn(phone: String, phoneCode: String) {
loginState.value = Outcome.success("")
}
fun getLoginState(): LiveData<Outcome<String>> = loginState
LoginViewModelTest class:
#RelaxedMockK
var SUT: LoginViewModel? = null
#Mock
var loginInteractor: LoginInteractor? = null
#Mock
var textValidator: TextValidator? = null
#Mock
var textProvider: TextProvider? = null
#Mock
var blinkUserPreferences: BlinkUserPreferences? = null
#get:Rule
var rule: TestRule = InstantTaskExecutorRule()
#RelaxedMockK
var mockObserver: Observer<Outcome<String>>? = null
#Before
fun setUp() {
MockKAnnotations.init(this, relaxUnitFun = true)
SUT = spyk(
LoginViewModel(
mockk<LoginInteractor>(),
mockk<TextValidator>(relaxed = true),
mockk<TextProvider>(),
mockk<BlinkUserPreferences>()))
mockObserver = mockk<Observer<Outcome<String>>>()
SUT!!.getLoginState().observeForever(mockObserver!!)
}
#Test
fun logIn() {
//Arrange
every {SUT!!.getLoginState().value} returns Outcome.success("")
//Act
SUT!!.logIn("89989676","89998")
//Assert
verify() { mockObserver!!.onChanged(Outcome.success("abc")) }
}
Question:
In verification, why onChanged method is not being called, or what does it mean that no answer found for Observer().onChanged, how can I notify my onChanged method so I can verify it?
After watching this: https://mockk.io/#answers. It says
specify that the matched call answers with a code block scoped with
answer scope
I just posted this:
every { mockObserver!!.onChanged(any()) } answers {}
in the following test function and it worked.
#Test
fun logIn() {
//Arrange
every { mockObserver!!.onChanged(any()) } answers {}
every {SUT!!.getLoginState().value} returns Outcome.success("abc")
//Act
SUT!!.logIn("89989676","89998")
//Assert
verify() { mockObserver!!.onChanged(Outcome.success("abc")) }
}
According to my understanding, if you mockk a function, and you want to use its particular function you must use the every expression to tell framework that it will answer, because framework needs to know that it needs to answer something.
And if you want that all behaviour functions should also be added with mock with their implementation then you must spyk your class so that it gets the behaviour as well and then you can easily use the function without using expression every.
Please note that every expression is used for many cases like to get a mocked result out of that function, or just need to tell the framework that this function should answers this.
Please correct me through comments if I'm wrong, Ill update it.

Mockk Mocking Private Properties in Kotlin

I have a simple class with a private field.
class EmployeeData {
private var employeeAge: Int = 0
fun getAge(): Int {
return 1 + employeeAge
}
}
I am trying to test this private employeeAge with the following from official docs
#Test
fun testPrivateAge() {
val mock = spyk(EmployeeData())
every {
mock getProperty "employeeAge"
} propertyType Int::class answers { fieldValue + 6 }
every {
mock setProperty "employeeAge" value any<Int>()
} propertyType Int::class answers { fieldValue += value }
every { mock getProperty "employeeAge" } returns 33
every { mock setProperty "employeeAge" value less(5) } just Runs
assertEquals(10,mock.getAge())
}
I am receiving such exception from MockK
io.mockk.MockKException: Missing calls inside every { ... } block.
at io.mockk.impl.recording.states.StubbingState.checkMissingCalls(StubbingState.kt:14)
at io.mockk.impl.recording.states.StubbingState.recordingDone(StubbingState.kt:8)
Any clue on what's I am doing wrong? Official docs suggest using such technique against private properties but for me it doesn't work and I'm using latest on this moment version of MockK which is v1.10.0.
Though for private methods it is working like a charm. I am able to test the private method in this logic.
This is a problem with some Kotlin optimisations. According to MockK author "Brief explanation. It is nearly impossible to mock private properties as they don't have getter methods attached. This is kind of Kotlin optimisation and solution is major change."
More info can be found on these 2 Github issues:
https://github.com/mockk/mockk/issues/263
https://github.com/mockk/mockk/issues/104

Error: None of the following functions can be called with the arguments supplied when converted to Kotlin from Java

I have seen other questions here related to this error but still not able to fix. Plus I'm asking this question because unlike other questions here, I'm getting this error only when I convert the code to Kotlin from Java.
I'm using this same RxJava code in Java, it works fine.
I converted to Kotlin and it gives this error -
Kotlin Compilation Error : None of the following functions can be
called with the arguments supplied
var observable : Observable<Bitmap> = Observable.just(bitmap)
var observer:Observer<Bitmap> = Observer<Bitmap>() {
fun onSubscribe(d: Disposable) {
disposable = d
}
fun onNext(orientedBitmap:Bitmap) {
// do something
}
fun onError(e:Throwable) {
}
fun onComplete() {
}
}
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
// It shows the error here
.subscribe(observer)
Can anyone explain what's wrong here?
It was a conflict in importing package. I'm also using Observer from architecture components. Import Observer of both the packages, it will be solved.
So, for this -
var observer:Observer<Bitmap> = Observer<Bitmap>()
It was taking the Observer from the architecture components.
I solved it by using it like this -
var observer = object : io.reactivex.Observer<Bitmap>

Categories

Resources