How to mock kotlin map function? - android

I'm trying to stub a kotlin extension .map:
private fun stubGetUsers(users: List<User>) {
val genericRawResult = mock<GenericRawResults<User>>()
whenever(genericRawResult.map { User() }).thenReturn(users)
usersDao.stub { on { it.queryRaw("", RawRowMapper { _, _ -> User() }) }.doReturn(genericRawResult) }
}
When I run the test, I'm getting a NullPointerException:
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
for (item in this)
destination.add(transform(item))
return destination
}
at line: for (item in this)
So I tried to mock the _Collections.kt class mapTo function:
val destination = arrayListOf<User>()
whenever<List<User>>(genericRawResult.mapTo(destination) { User() }).thenReturn(destination)
But still getting the error:
java.lang.NullPointerException
at com.myapp.UserRepositoryTest.stubGetUsers(UserRepositoryTest.kt:144)
at com.myapp.UserRepositoryTest.testGetAllUsers(UserRepositoryTest.kt:66)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
In order to get a detailed error, I've made the following changes:
genericRawResult.stub { onGeneric { it.mapTo(arrayListOf()) { User() } }.doReturn(arrayListOf()) }
genericRawResult.stub { on { it.map { User() } }.doReturn(users) }
And this is the error that I get:
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
ArrayList cannot be returned by iterator()
iterator() should return Iterator
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.

Related

Problems with Kotlin Result<T> on unit tests

I am working on an android Application and I opted to use Kotlin Result class so as to handle success/failure on my operations. I made the changes to the code, but the tests stop working and I cannot understand why. Here I show you some snippets:
FireStoreClient.kt
suspend fun items(): Result<ItemsResponse>
NetworkDataSource.kt
suspend fun getItems(): List<Item> =
fireStoreClient.items().fold({ it.items.map { item -> item.toDomain() } }, { emptyList() })
NetworkDataSourceTest.kt
#ExperimentalCoroutinesApi
#Test
fun `Check getItems works properly`() = runBlockingTest {
whenever(fireStoreClient.items()).doReturn(success(MOCK_ITEMS_DOCUMENT))
val expectedResult = listOf(
Item(
id = 1,
desc = "Description 1"
),
Item(
id = 2,
desc = "Description 2"
)
)
assertEquals(expectedResult, dataSource.getItems())
}
And this is the exception I am getting right now. Any clue? It appears that the fold() method is not being executed when unit testing.
java.lang.ClassCastException: kotlin.Result cannot be cast to ItemsResponse
at NetworkDataSource.getItems(NetworkDataSource.kt:31)
I've found a different workaround for this result-wrapping issue, for those who don't want to make their own Result type.
This issue appears to happens specifically when using Mockito's .thenReturn on suspend functions. I've found that using .thenAnswer doesn't exhibit the problem.
So instead of writing this in your unit test (changed doReturn to thenReturn here):
whenever(fireStoreClient.items()).thenReturn(success(MOCK_ITEMS_DOCUMENT))
Use:
whenever(fireStoreClient.items()).thenAnswer { success(MOCK_ITEMS_DOCUMENT) }
Edit: I should note that I was still experiencing this issue when running Kotlin 1.5.0.
Edit: On Kotlin 1.5.20 I can use .thenReturn again.
After a deep dive into the problem, finally, I've found a temporary workaround that works in the testing environment. The problem is, somehow the value of the Result object is wrapped by another Result, and we can pull the desired value or exception using reflection.
So, I've created an extension function called mockSafeFold, which implements the fold behavior in normal calls, and acts fine when you are executing unit-tests.
inline fun <R, reified T> Result<T>.mockSafeFold(
onSuccess: (value: T) -> R,
onFailure: (exception: Throwable) -> R
): R = when {
isSuccess -> {
val value = getOrNull()
try {
onSuccess(value as T)
} catch (e: ClassCastException) {
// This block of code is only executed in testing environment, when we are mocking a
// function that returns a `Result` object.
val valueNotNull = value!!
if ((value as Result<*>).isSuccess) {
valueNotNull::class.java.getDeclaredField("value").let {
it.isAccessible = true
it.get(value) as T
}.let(onSuccess)
} else {
valueNotNull::class.java.getDeclaredField("value").let {
it.isAccessible = true
it.get(value)
}.let { failure ->
failure!!::class.java.getDeclaredField("exception").let {
it.isAccessible = true
it.get(failure) as Exception
}
}.let(onFailure)
}
}
}
else -> onFailure(exceptionOrNull() ?: Exception())
}
Then, simply call it instead of fold:
val result: Result = myUseCase(param)
result.mockSafeFold(
onSuccess = { /* do whatever */ },
onFailure = { /* do whatever */ }
)
I had the same issue.
I noticed that my method of injected class which should return Result<List<Any>> returns actually Result<Result<List<Any>>> which causes the ClassCastException. I used the Evaluate Expression option for the result from the method and I got
Success(Success([]))
The app works well but unit tests didn't pass due this problem.
As a temporary solution I built a new simple implementation of Result sealed class with fold() extension function. It should be easy to replace in future to kotlin.Result
Result sealed class:
sealed class Result<T> {
data class Success<T>(val value: T) : Result<T>()
data class Failure<T>(val error: Throwable) : Result<T>()
}
fold() extension function:
inline fun <R, T> Result<T>.fold(
onSuccess: (value: T) -> R,
onFailure: (exception: Throwable) -> R
): R = when (this) {
is Result.Success -> onSuccess(value)
is Result.Failure -> onFailure(error)
}

Coroutines - Function vs Procedure

When transforming (async function that needs to do some backgorund work to return a value) to sync function with coroutines one can use suspendCoroutine, as in the following extension i did to FusedLocationProviderClient :
private suspend fun FusedLocationProviderClient.colastLocation(): Location = suspendCoroutine {
lastLocation.addOnSuccessListener { l -> l?.run { it.resume(l) } ?: run{ it.resumeWithException(Exception("location is null"))} }.addOnFailureListener { e -> it.resumeWithException(e) }
}
But what if i want to make an async procedure run sync? (procedure = function that i dont care of its returned value, i just want to wait for it to finish)
I can still use suspendCoroutine as i did for addGeofence here:
private suspend fun GeofencingClient.coaddGeofences(geofencingRequest: GeofencingRequest, broadcast: PendingIntent?) : Void = suspendCoroutine {
addGeofences(geofencingRequest,broadcast).addOnSuccessListener { v -> it.resume(v) }.addOnFailureListener { e -> it.resumeWithException(e) }
}
But it feels a little hacky working with that Void object, maybe there is a more natural way to do that? e.g run async job and make it sync with coroutines when i dont care for the value (if returned - its a success, else it would throw an exception).
Theoretically i would expect doing something like that :
private suspend fun GeofencingClient.coaddGeofences(geofencingRequest: GeofencingRequest, broadcast: PendingIntent?) = suspendCoroutine {
addGeofences(geofencingRequest,broadcast).addOnSuccessListener { v -> it.resume() }.addOnFailureListener { e -> it.throwException(e) }
}
As Moira has mentioned, you can just use Kotlin's Unit object. From Unit `s Javadoc:
The type with only one value: the Unit object. This type corresponds to the void type in Java.
So your procedure code will look like:
private suspend fun GeofencingClient.coaddGeofences(geofencingRequest: GeofencingRequest, broadcast: PendingIntent?) = suspendCoroutine<Unit> {
addGeofences(geofencingRequest,broadcast).addOnSuccessListener { it.resume(Unit) }.addOnFailureListener { e -> it.resumeWithException(e) }
}

Does Kotlin `by` keyword work for nullable delegate?

I've pretty excited by Kotlin compiler features and by by in particular - it saves time generating gelegating code:
https://kotlinlang.org/docs/reference/delegation.html
But i want delegate to be nullable and delegating code to check if it's null first and return if it is:
interface Base {
val message: String
fun print()
}
class BaseImpl(val x: Int?) : Base {
override val message = "BaseImpl: x = $x"
override fun print() { println(message) }
}
class Derived(b: Base?) : Base by b {
// This property is not accessed from b's implementation of `print`
override val message = "Message of Derived"
}
fun main() {
val b = BaseImpl(10)
val derived = Derived(b)
derived.print()
println(derived.message)
}
When compiling ^ i'm getting Type mismatch: inferred type is Base? but Base was expected.
Is it still possible with Kotlin?
To be more detailed i'd like Kotlin compiler to generate forwarding calls to wrapped impl (extWebChromeClient) in https://developer.android.com/reference/android/webkit/WebChromeClient like follows:
private WebChromeClient intWebChromeClient = new WebChromeClient()
{
#Override
public void onReceivedTitle(WebView view, String title)
{
if (extWebChromeClient != null)
{
extWebChromeClient.onReceivedTitle(view, title);
}
}
...
You can make this yourself using dynamic proxies, though I wouldn't really recommend it. Note that for non-void methods there's no way to require overriding them. The below implementation just throws exceptions for them unconditionally, but you could still call them for non-null x.
inline fun <reified T : Any> nullableProxy(x: T?): T {
val handler = InvocationHandler { _, method, args ->
if (method.returnType == Void.TYPE) {
if (x != null) {
method.invoke(x, *(args ?: arrayOf()))
}
} else
throw UnsupportedOperationException("Non-void method")
}
return Proxy.newProxyInstance(
T::class.java.classLoader,
arrayOf(T::class.java),
handler) as T
}
class Derived(b: Base?) : Base by nullableProxy(b)
This also won't perform as well as implementing methods directly would.

Kotlin - How to properly map result using Either?

I'm trying to read a list of objects from the database and mapping it to another type of list.
// Returns either a Failure or the expected result
suspend fun getCountries(): Either<Failure, List<CountryItem>> {
// Get the result from the database
val result = countryLocalDataSource.getCountries()
// Left means Failure
if (result.isLeft) {
// Retrieve the error from the database
lateinit var error: Failure
result.either({
error = it
}, {})
// Return the result
return Either.Left(error)
}
// The database returns a List of Country objects, we need to map it to another object (CountryItem)
val countryItems: MutableList<CountryItem> = mutableListOf()
// Iterate the Country List and construct a new List of CountryItems
result.map { countries -> {
countries.forEach {
// Assign some values from an Enum (localized string resources)
val countryEnumValue = Countries.fromId(it.id)
countryEnumValue?.let { countryIt ->
val countryStringNameRes = countryIt.nameStringRes;
// Create the new CountryItem object (#StringRes value: Int, isSelected: Bool)
countryItems.add(CountryItem(countryStringNameRes, false))
}
}
} }
// Because this is a success, return as Right with the newly created List of CountryItems
return Either.Right(countryItems)
}
For the sake of readability I didn't included the whole Repository or the DAO classes and I have left comments in the code snippet above.
In a nutshell: I'm using Kotlin's Coroutines for accessing the database in a separated thread and I'm handling the response on the UI Thread. Using the Either class in order to return two different results (failure or success).
The above code works, however It's too ugly. Is this the right approach to deliver the result?
What I'm trying to do is to refactor the code above.
The whole problem is caused by the two different object types. The Database Data Source API is returning an Either<Failure, List<Country>>, meanwhile the function is expected to return an Either<Failure, List<CountryItem>>.
I can't deliver a List<CountryItem> directly from the Database Data Source API, because Android Studio doesn't let me compile the project (entities implementing interfaces, compile error, etc.). What I'm trying to achieve is to map the Either result in a nicer way.
Try using Kotlin's Result
So in your case you can write something like:
return result.mapCatching { list: List<Country> -> /*return here List<CountryItem>>*/ }
And for checking result call:
result.fold(
onSuccess = {...},
onFailure = {...}
)
In order to invoke a constructor you should call Result.success(T) or Result.failure(Throwable)
Unfortunately, you'll also need to suppress use-as-return-type warnings How to
You can simplify by checking the type of Either and accessing the value directly. In your case:
access Left via result.a -> Failure
access Right via result.b -> List<Country>
ex:
when (result) {
is Either.Left -> {
val failure: Failure = result.b
...
}
is Either.Right -> {
val countries: List<Country> = result.b
...
}
}
An alternative is to use the either() function (normally this is called fold()):
result.either(
{ /** called when Left; it == Failure */ },
{ /** called when Right; it == List<Country> */ }
)
Assume your Country class is defined as follow:
data class Country(val name: String) {}
and your CountryItem class is defined as follow:
data class CountryItem(private val name: String, private val population: Int) {}
and your CountryLocalDataSource class with a method getCountries() like this:
class DataSource {
suspend fun getCountries(): Either<Exception, List<Country>> {
return Either.Right(listOf(Country("USA"), Country("France")))
//return Either.Left(Exception("Error!!!"))
}
}
then the answer to your question would be:
suspend fun getCountryItems(): Either<Exception, List<CountryItem>> {
when (val countriesOrFail = DataSource().getCountries()) {
is Either.Left -> {
return Either.Left(countriesOrFail.a)
}
is Either.Right -> {
val countryItems = countriesOrFail.b.map {
CountryItem(it.name, 1000)
}
return Either.Right(countryItems)
}
}
}
To call your getCountryItems(), here is an example:
suspend fun main() {
when (val countriesOrFail = getCountryItems()) {
is Either.Left -> {
println(countriesOrFail.a.message)
}
is Either.Right -> {
println(countriesOrFail.b)
}
}
}
Here's the sample code in the playground: https://pl.kotl.in/iiSrkv3QJ
A note about your map function:
I'm guessing you don't actually need the result to be a MutableList<CountryItem> but you had to define so because you want to add an element as you iterate through the input list List<Country>.
Perhaps the following is the case: If you have a List<Country> with 2 elements like in the example, and you want to map so that the result becomes a List<CountryItem> with also 2 corresponding elements, then you don't need to call forEach inside a fun that gets passed to the higher-order function map. But this may be an entirely new question.

How to check if the result of an expression is used in a custom Android lint rule

I'm trying to write a lint rule to catch places where the result of an RxJava2 function is not used in anyway. For example:
final Observable<String> observable = getObservable();
observable.subscribe(this::onSuccess, this::onError);
In RxJava2, the subscribe function returns a Disposable that should be used to unsubscribe if the program/class instance "finishes" in some way in order to prevent memory leaks. I want to fail my build if any occurences like this are found.
This particular method (and all of the other ones I'm interested in) is annotated with io.reactivex.annotations.CheckReturnValue:
#CheckReturnValue
#SchedulerSupport(SchedulerSupport.NONE)
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {
return subscribe(onNext, onError, Functions.EMPTY_ACTION, Functions.emptyConsumer());
}
My plan is to write a custom lint rule that:
Searches for expressions that return the result of a method annotated with io.reactivex.annotations.CheckReturnValue
Filter the searches down to only expressions whose result is never used
For example, here are some cases that should not fail:
final CompositeDisposable compositeDisposable = new CompositeDisposable();
// Result of subscribe passed into another function
compositeDisposable.add(observable.subscribe(this::onSuccess, this::onError).dispose());
// Result of subscribe stored in a variable
final Disposable disposable = observable.subscribe(this::onSuccess, this::onError);
// Result of subscribe used
observable.subscribe(this::onSuccess, this::onError).dispose();
I've managed to write a lint rule that finds instances of call expressions where the result is annotated with CheckReturnValue, but I'm struggling to figure out how to use the JetBrains UAST/PSI APIs to work out if the result is used. This is my rule so far:
class RxJava2CheckReturnValueMethodNotAssigned : Detector(), Detector.UastScanner {
override fun getApplicableUastTypes() = listOf(UCallExpression::class.java)
override fun createUastHandler(context: JavaContext) = CheckReturnValueVisitor(context)
class CheckReturnValueVisitor(private val context: JavaContext) : UElementHandler() {
override fun visitCallExpression(node: UCallExpression) {
val method = node.resolve() ?: return
if (!isCheckReturnValueAnnotatedMethod(method)) {
return
}
if (!isResultOfCallUsed(node)) {
return
}
reportIssue(node)
}
private fun isCheckReturnValueAnnotatedMethod(method: PsiMethod): Boolean {
return context.evaluator.getAllAnnotations(method, true)
.any { "io.reactivex.annotations.CheckReturnValue" == it.qualifiedName }
}
private fun isResultOfCallUsed(node: UCallExpression): Boolean {
// Need to check is the result of the expression is used in some way
return false
}
private fun reportIssue(node: UCallExpression) {
// SNIP...
}
}
}
This currently doesn't work because it reports all usages of any function annotated with CheckReturnValue.
As far as I know, node.resolve() often return null

Categories

Resources