ArgumentMatchers in MockK - android

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>()) }
}

Related

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)

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()

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

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)

Kotlin about passing lambda as property

I am confusing about merit of writing code as following 2 case:
class TestA {
private val foo: Boolean by lazy {
// Here is logic that return true or false
}
Case 1:
fun main() {
TestB({foo})
}
Case 2:
fun main() {
TestB(foo)
}
}
Case 1:
class TestB(private val isFoo: () -> Boolean ) {
fun checkFoo(): Boolean {
return isFoo.invoke()
}
}
Case 2:
class TestB(private val isFoo: Boolean ) {
fun checkFoo(): Boolean {
return isFoo
}
}
When should I use case 1 or case 2 ?
By the way, please let me know how does invoke() method work?
You only pass lambdas into other class constructors if you want something to be invoked on the other end, that might make sense if used as a callback, or if you need to have a function that creates objects again and again rather than being static. In this case, you'd store the lambda for later referral and invoke it whenever needed. If you just pass a static instance around, that is for example foo in your code, there's no reason for a lambda. You should always prefer not to use lambdas for constructors; scenarios in which they are useful or necessary are rather rare IMO.
As to your question regarding invoke: Kotlin has a number of functions that work "by convention", e.g. rangeTo, equals, contains, compareTo, the index operators and also invoke. Learn about conventions here.
Now, whenever a class provides the invoke operator, you can call instances of that class as if they were functions:
class InvokeMe(){
operator fun invoke(value: Int) = println("invoked with $value")
}
val obj = InvokeMe()
//both are compiled to the same code
obj(10)
obj.invoke(5)
Since every lambda is being compiled into a Function instance (see kotlin.jvm.functions) which comes with an implementation of invoke, you can call lambdas as shown above, i.e., using lambda(args) or lambda.invoke(args)
.invoke() will simply call your lambda and give your result, same as calling a function.
As for when you should pass a lambda or an actual value, it very depends.
Personally, I would only suggest using lambdas in very specific situations, overusing them can make your code very confusing and hard to refactor. If you just want a result to be passed into the function, just pass the actual value. Don't make someone else call .invoke().
But a few good example for a lambda are callsbacks, or onClickListeners.
// A login network request with a lambda handling the result.
fun login( username: String, password: String, onResult: (Result) -> Unit ) {
// do some network call, and return a Result.
}
// note: if the last param is a lambda, you can simply move it outside the function call like this.
login( username, password ) { result ->
// use the result of the network request.
}
Hopefully that helps.

How to pass null to an Observable with nullable type in RxJava 2 and Kotlin

I initialize my variable like this:-
val user: BehaviorSubject<User?> user = BehaviorSubject.create()
But I can't do this. IDE throws an error:-
user.onNext(null)
And doing this, IDE says u will never be null:-
user.filter( u -> u!=null)
As Guenhter explained, this is not possible. However, instead of proposing the null-object pattern, I'd recommend an implementation of the Optional type:
data class Optional<T>(val value: T?)
fun <T> T?.asOptional() = Optional(this)
This makes your intent much clearer, and you can use a destructuring declaration in your functions:
Observable.just(Optional("Test"))
.map { (text: String?) -> text?.substring(1)?.asOptional() }
.subscribe()
Using the null-object pattern here can cause more bugs than it solves.
If you use rxkotlin/rxjava 2.0 (I assume so) than the answer is: you can't. The reason is explained here.
This is a break of the interface. Have a look at the Observable Interface
public interface Observer<T> {
/** ... */
void onSubscribe(#NonNull Disposable d);
/** ... */
void onNext(#NonNull T t);
/** ... */
void onError(#NonNull Throwable e);
/** ... */
void onSubscribe(#NonNull Disposable d);
/** ... */
void onNext(#NonNull T t);
/** ... */
void onError(#NonNull Throwable e);
...
The #NonNull will be considered by the Kotlin compiler and therefore you CAN'T pass null.
Even if you could, the onNext would immediately throw an error:
#Override
public void onNext(T t) {
if (t == null) {
onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources."));
return;
}
...
}
If you really need such a thing as null you have to fake it. e.g. by creating a static object of User which represents your null-element.
e.g.
data class User(val username, val password) {
companion object {
val NULL_USER = User("", "")
}
}
...
val user = BehaviorSubject.create<User>()
...
user.onNext(User.NULL_USER)
...
user.filter { it !== User.NULL_USER }
But if is somehow possible, try to avoid the null concept and maybe think of another solution where this isn't needed.
Thank you very much for all your answers but I ultimately went with this solution:-
class UserEnvelope(val user:User?) {}
And using this in the observables.
This best suited my requirements.
I am new to Kotlin so I don't know how to use Optionals. But from what I understand, I would have to typecast it to User type everytime I need to observe the values right?
To implement the solution mentioned in the nhaarman's answer, you can use the util class Optional (doc) from the Android SDK which was added in API level 24.
If your app's minSdkVersion less than 24 then you still need to implement it by yourself.
Since RxJava 2 does not support null values, there are some other acceptable solutions you can use:
Work with a custom or third party wrapper library of Optionals like some of the posted answers suggest. When I got rid of Java in favour of Kotlin, Optionals went away in the same package since Kotlin per se supports nullability as part of its type System. Just by this change the code was much more clearer, and I personally don't want to get Optionals back in my code as long as I can avoid them.
Emit Any class instances with your subject type. For example you could create an Empty.INSTANCE enum class which would emulate the null value and then filter by the enum class.
The last one is the one I use and prefer being a variant of the previous solution and is based on specialisations. Our friends of JetBrains always emphasise that classes are very cheap in Kotlin, so this would be a quick example to distinguish logged users and not logged ones:
abstract class SessionUser
sealed class LoggedUser(val username: String, val password: String) : SessionUser()
sealed class LogoutUser : SessionUser()
private val user = BehaviorSubject.create<SessionUser>()
private val loggedUser =
user.filter { it is LoggedUser }.cast(LoggedUser::class.java)
fun login(username: String, password: String) {
user.onNext(LoggedUser(username, password))
}
fun logout() {
user.onNext(LogoutUser())
}
I've taken an approach similar to Optional<User> and UserEnvelope. I make a simple User class and a ReifiedUser class that inherits from it. The User class has a companion object that has a NONE instance. The BehaviorSubject is instantiated with the User.NONE instance. It looks something like this:
open class User {
companion object {
val NONE = User()
}
}
class ReifiedUser(
#field:JsonProperty(J.FirstName) val firstName: String,
#field:JsonProperty(J.LastName) val lastName: String
) : User()
My BehaviorSubject is instantiated like this:
val activeUser: BehaviorSubject<User> = BehaviorSubject.createDefault(User.NONE)
And wherever I need to use activeUser I either flatMap it to Observable.empty() if it's NONE or just figure out what it is and what to do in the subscriber.
I don't like mixing java Optional with kotlin nullable because mixing map and let gets really confusing and ugly. This way it's very obvious what's going on.
I think it makes more sense to write a container class such as Result. An example of that would be
data class Result<T>(value: T?, error: Throwable?)
Usage
Observable.create { observer ->
upstreamService.listen(object: UpstreamListener {
onSuccess(data: User) {
observer.onSuccess(Result(data))
}
onError(exception: Throwable) {
observer.onSuccess(Result(null, exception))
}
}
}

Categories

Resources