MockK - Failed matching mocking signature for left matchers: [any(), any()] - android

I want to implement some UI Tests to assure that the code implemented today works for tomorrow but when trying to see if already UI tests implemented in the past works, it throws this error:
Caused by: io.mockk.MockKException: Failed matching mocking signature for left matchers: [any(), any()]
This happens on an every {} return Unit line which there's a object file called WakeUpTimeManager, that calls a .set(param1, param2) function and inside that function there are some inline functions which I think it could be causing the problem but I don't know. I tried searching on the internet but couldn't find a solution.
Here's the test that throws the error:
#Before
fun setup() {
mockkObject(WakeUpTimerManager)
every { WakeUpTimerManager.set(any(), any()) } returns Unit
}
Here's the function that is calling on every line
fun set(context: Context, timer: Timer) {
if (timer.atMillis < System.currentTimeMillis()) {
return
}
if (Preset.findByID(context, timer.presetID) == null) {
return
}
//This is an inline function
withGson {
PreferenceManager.getDefaultSharedPreferences(context).edit {
putString(PREF_WAKE_UP_TIMER, it.toJson(timer))
}
}
//This is an inline function
withAlarmManager(context) {
it.setAlarmClock(
AlarmManager.AlarmClockInfo(timer.atMillis, getPendingIntentForActivity(context)),
getPendingIntentForService(context, timer)
)
}
}
Question: Why does mockk throw this error? What's going on? Is there any solution for this?

try with mockkStatic(WakeUpTimerManager::class). For me mockkObject was not working either, but mockkStatic did

In my case I was using the wrong annotation for mocking dependencies.
I was using #MockBean from org.springframework.boot.test.mock.mockito.MockBean while I should have been using #MockkBean from com.ninjasquad.springmockk.MockkBean.

In my case I used type cast for any(). I wanted to test that a method viewModel.show(Message()) had invoked. But this method is overloaded (has signatures of different types), so I tried to cast parameter any() to Message.
// show is overloaded method
fun show(resourceId: Int) {}
fun show(text: String) {}
fun show(message: Message) {}
// But it threw the exception.
verify { viewModel.show(any() as Message) }
// This won't work because Message() object will be different
verify { viewModel.show(Message()) }
Maybe mocking for message will help, but not in my case.
// val message = mockk<Message>()
// every { Message() } returns message
// verify { viewModel.show(message) }
I had to add mockkStatic, because I used an extension method. For instance, fun ViewExtension.show():
mockkStatic(ViewExtension::class.java.name + "Kt") // Like "com.example...ViewExtensionKt"
Then mock a behaviour:
every { viewModel.show(Message()) } just Runs
verify { viewModel.show(any() as Message) }

Sometimes, especially with Dagger Hilt and global test modules that replace object instances with Mockk mocks, it's not entirely clear whether one works with the mock or the real object. For me it was exactly this - I had a missing dependency, so my real instance was not replaced with the mocked instance, so mockk answered with this really weird error:
io.mockk.MockKException: Failed matching mocking signature for
left matchers: [any()]
at io.mockk.impl.recording.SignatureMatcherDetector.detect(SignatureMatcherDetector.kt:99)
at io.mockk.impl.recording.states.RecordingState.signMatchers(RecordingState.kt:39)
at io.mockk.impl.recording.states.RecordingState.round(RecordingState.kt:31)
at io.mockk.impl.recording.CommonCallRecorder.round(CommonCallRecorder.kt:50)
at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:63)
at io.mockk.impl.eval.VerifyBlockEvaluator.verify(VerifyBlockEvaluator.kt:30)
at io.mockk.MockKDsl.internalVerify(API.kt:119)
at io.mockk.MockKKt.verify(MockK.kt:149)
at io.mockk.MockKKt.verify$default(MockK.kt:140)

Related

Mocking of my companion object's function seems not to work for Unit tests and mockk library

I have a custom Logger used thorough the application. It is doing more, but it can be simplified as:
class MyLogger {
companion object {
fun d(tag: String, msg: String): Int {
return Log.d(tag, msg)
}
}
}
Again, for simplicity, asume a function like the following:
fun addWithLogger(val1: Int, val2: Int): Int {
MyLogger.d("TEST", "adding $val2 to $val1")
return (val1 + val2).also {
MyLogger.d("TEST", "result $it")
}
}
I am trying to test the function using JUnit, and mock the MyLogger.d function using mockk library:
#Test
fun additionWithLogger_isCorrect() {
val testClass = TestClass()
mockkStatic(MyLogger::class)
every { MyLogger.d(any(), any()) } returns 0
assertEquals(5, testClass.addWithLogger(2, 3))
}
I have tried with mockkStatic, mockkObject, with MyLogger.Companion etc, but all my attempts are resulting in something simillar:
Method d in android.util.Log not mocked. See http://g.co/androidstudio/not-mocked for details.
java.lang.RuntimeException: Method d in android.util.Log not mocked. See http://g.co/androidstudio/not-mocked for details.
at android.util.Log.d(Log.java)
at example.MyLogger$Companion.d(MyLogger.kt:8)
at example.ExampleUnitTest$additionWithLogger_isCorrect$1.invoke(ExampleUnitTest.kt:25)
at example.ExampleUnitTest$additionWithLogger_isCorrect$1.invoke(ExampleUnitTest.kt:25)
at io.mockk.impl.eval.RecordedBlockEvaluator$record$block$1.invoke(RecordedBlockEvaluator.kt:25)
at io.mockk.impl.eval.RecordedBlockEvaluator$enhanceWithRethrow$1.invoke(RecordedBlockEvaluator.kt:78)
at io.mockk.impl.recording.JvmAutoHinter.autoHint(JvmAutoHinter.kt:23)
at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:40)
at io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:30)
at io.mockk.MockKDsl.internalEvery(API.kt:94)
at io.mockk.MockKKt.every(MockK.kt:143)
at example.ExampleUnitTest.additionWithLogger_isCorrect(ExampleUnitTest.kt:25)
...
It seems, that the MyLogger.d function is still being invoked, despite I am trying to mock it? What am I missing?
I have tried mockito and mockk libraries, but with no luck. I would like to test the functionality using Unit tests on PC. Tests are running ok as instrumental on Android device.
Code to be tested is already written, so I do not have much possibilities to adjust the MyLogger inside...

How to unit test function that references CookieManager?

The application in question has a logout function that among other things, performs a call to CookieManager.getInstance().removeAllCookies(null):
fun logout(...) {
showLoader(true)
msgRepo.unregisterSendBirdHandlersAndPushToken(
onSuccess = {
clearUserData(...)
// ...
onLogout()
},
onFailure = {
clearUserData(...)
// ...
onLogout()
}
)
}
/**
* Helper to clear user data before logging user out
*/
private fun clearUserData(...) {
// ...
CookieManager.getInstance().removeAllCookies(null)
}
Two tests reference the aforementioned logout function. They both are quite similar and look a bit like this:
#Test
fun `verify logout with success`() {
// .. Other code
HardLogoutHelper.logout(...)
// ...
}
The tests fail with the following error message:
'void android.webkit.CookieManager.removeAllCookies(android.webkit.ValueCallback)'
java.lang.NoSuchMethodError: 'void android.webkit.CookieManager.removeAllCookies(android.webkit.ValueCallback)'
at com.example.helpers.HardLogoutHelper.clearUserData(HardLogoutHelper.kt:86)
I've tried running the test with Roboelectric via #RunWith(RoboelectricTestRunner::class) and I have have tried creating a custom Roboelectric Shadow for the CookieManager class. The issue seems to persist even when using Roboelectric.
Why is the previously mentioned error message being thrown, and how can it be fixed?

doNothing() does not work when i want to mock data and test UI Fragment

I am going to test fragment with Espresso then i want to mock viewmodels and members.
In my viewModel i have a void function like this :
fun getLoginConfig() {
viewModelScope.launchApiWith(_loginConfigLiveData) {
repository.getLoginConfig()
}
}
In test fragment when we call getLoginConfig() from viewModel i want to mock it with doNothing() but i faced with this error :
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, which is not supported
3. you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed
At this line on testFragmentClass :
#Before
fun setUp() {
//logOut
mockVm = mock(SplashVM::class.java)
loadKoinModules(module {
single {
mockVm
}
})
}
doNothing().`when`(mockVm.getLoginConfig()).let {
mockVm.loginConfigLiveData.postValue(Resource.Success(
LoginConfigResponse(
listOf("1"),1,1,"1",true)
))
}
A few things:
doNothing just does nothing, which is unnecessary for void methods on a mock. It's the default behavior. You only want doNothing for spies or already-stubbed mocks.
If you want something specific to happen in response to a call on a mock, doAnswer is the way to go.
In doVerb syntax, Mockito expects that there is only a variable there; the expression should not call a method on a mock, or else Mockito thinks you've lost interest and throws UnfinishedStubbingException.
Therefore your fix looks like:
doAnswer {
mockVm.loginConfigLiveData.postValue(Resource.Success(
LoginConfigResponse(
listOf("1"),1,1,"1",true)
))
}.`when`(mockVm).getLoginConfig()

ArgumentMatchers in MockK

I'm converting from Java to Kotlin, and from Mockito to MockK.
I'm stuck at converting Argument Matchers from Mockito to MockK.
Mockito can do any() to match anything, including nulls and varargs. (imports ArgumentMatchers.any)
For example:
verify(object1).store(any(SomeClass.class));
Does MockK have anything for that? In this specific situation, it's not any primitive type. I'm trying to match a class Object.
Thank you!
If you want to match a specific type, you could do
verify { object1.store(ofType(SomeClass::class)) }
In mockk, you can any() like this.
verify { object1.store(any()) }
In the case of migrate of Mockito to Mockk, consider the following:
With Mockito is encapsuled the class inside verify method, for example:
verify(object1).store(any(SomeClass.class));
In Mockk use lambda with receiver, similar to apply function (but without return), for example:
verify{ object1.store(any<SomeClass::class>()) }
And response your question, for specify the type can use any<YourType::class>, although the compiler marks it as unnecessary code because it has type inference, This is mainly useful when you have overloaded a function, so you can differentiate which parameters to receive for each one, for example:
class YourClass {
fun someMethod(value: String) {
}
fun someMethod(value: Int) {
}
}
fun test() {
val mock: YourClass = mockk()
verify { mock.someMethod(any<String>()) }
verify { mock.someMethod(any<Int>()) }
}

How to test constraints on object initialization?

I am writing an App for Android, and I am wanting to start writing tests for the classes I am writing. I am fairly new to writing test cases.
Right now to create a test, I use IntelliJ and use it's wizard to make a new JUnit4 test. The wizard allows me to select methods from my class to test.
But for the object I am testing, I do not want a negative number passed to the constructor.
class MinuteTime(private val minutes : Int) {
init {
if (minutes < 0) {
throw IllegalArgumentException("Cannot be less than 0.")
}
}
...
Where in my Test class is the best place to test these constraints? I know that to test the constraints, I just need to make sure the exception is thrown and caught, but I am unsure if I should make a new method for this, or just wedge it into one of the functions IntelliJ pre-made for me. Here is the generated test class:
class MinuteTimeTest {
#Test
fun getTimeInMinutes() {
}
#Test
fun getHours() {
}
#Test
fun getMinutes() {
}
#Test
fun plus() {
}
}
I'd definetly recommend to wrap this into a separate test method. Its concern is simply testing the validation during initialization:
#Test
fun negativeNumberConstructorTest() {
assertFailsWith(IllegalArgumentException::class){
MinuteTime(-1)
}
}
It’s using kotlintest on top of JUnit

Categories

Resources