Kotlin Mockk : Unable to mock a list correctly - list

I am trying to verify that .shuffled() on a list is called, but get an error on running because of a prior .take(6) call on the list, and I cannot see a way around this.
Here is some code that gets the same error:
val mockList =
mockk<List<String>> { every { shuffled() } returns mockk(relaxed = true) }
val choiceList = spyk(listOf("String1", "String2")) { every { take(6) } returns mockList }
val tmp = choiceList.take(6)
val tmp2 = tmp.shuffled()
verify {mockList.shuffled())
On line 4, I get the following error:
class io.mockk.renamed.java.util.List$Subclass0 cannot be cast to class java.lang.Integer (io.mockk.renamed.java.util.List$Subclass0 is in unnamed module of loader 'app'; java.lang.Integer is in module java.base of loader 'bootstrap')
Attempting to go around by directly verifying on choiceList.take(6).shuffled() and combining the two tmp vals into one has had no success, as it gets true whether or not .shuffled() gets called. Also, switching from a spy to a mock for choiceList has also not worked.
Edit: Note, since this is a toy example, the take() is completely necessary, and cannot be removed, as it has real use in the actual code.

Interesting one!
I think in current implementation it is not possible. The easy answer would be "this test misses the declaration of wrapping static class" (as extension methods are just the same as java static methods for JVM). But if we add it...
#Test
fun test() {
mockkStatic("kotlin.reflect.jvm.internal.impl.utils.CollectionsKt")
val iterClass = mockkClass(Iterable::class)
val mockList = mockk<List<String>> { every { shuffled() } returns mockk(relaxed = true) }
with(iterClass) {
every { take(6) } returns mockList
val tmp = take(6)
val tmp2 = tmp.shuffled()
verify {
mockList.shuffled()
}
}
}
we have a Recursion detected in a lazy value under LockBasedStorageManager#1d2ad266 (DeserializationComponentsForJava.ModuleData) which is understandable - we just mocked the whole extensions package. And it is not possible to mock only one extension method leaving others intact. (source: https://github.com/mockk/mockk#extension-functions)
However, I'd do the following. Why not make our own extension functions which call the original and mock those?
It would go like this:
Main.kt:
package root
...
fun <T> Iterable<T>.take(n: Int): Iterable<T> {
val m = Iterable<T>::take
return m.call(this)
}
fun <T> Iterable<T>.shuffled(): Iterable<T> {
val m = Iterable<T>::shuffled
return m.call(this)
}
Test.kt:
package root
...
#Test
fun test() {
// note this changed
mockkStatic("root.MainKt")
val iterClass = mockkClass(Iterable::class)
val mockList = mockk<List<String>> { every { shuffled() } returns mockk(relaxed = true) }
with(iterClass) {
every { take(6) } returns mockList
val tmp = take(6)
val tmp2 = tmp.shuffled()
verify {
mockList.shuffled()
}
}
}
The only downside here I think is that it's reflection (duh!) So, this can possibly affect performance and has the requirement to have implementation(kotlin("reflect")) in the dependencies (to use call()). If it is not feasible I think there's no clean solution.

val mockList: List<String> = mockk(relaxed = true)
mockList.shuffled()
verify { mockList.shuffled() }
This works for me. The problem is that take of choiceList cannot be mocked somehow. Is that really necessary?

Related

How to unit test Kotlin coroutines with multiple async calls

I'm trying to write some unit tests for the following Kotlin code which uses async to create coroutines:
class ClassToTest(val dependency1: Dependency1, val dependency2: Dependency2) {
fun funToTest(list: List<X>) {
runBlocking {
val deferreds: List<Deferred<Type>> = list.map { item ->
async(Dispatchers.Default) {
val v1 = dependency1.func1(item)
val v2 = dependency2.func2(v1)
someFunc(v2)
}
}
val results = deferreds.awaitAll()
}
}
}
I mocked both dependency1 and dependency2 in the unit testing and provided a list of 2 items as input to the funToTest. I also mocked how the dependencies should return values based on different input, something like below
val slot1 = slot<>()
every {dependency1.func1(capture(slot1))} answers {
if (slot1.captured.field == xxx) {
return1
} else {
return2
}
}
//similar thing for dependency1
// invoke funToTest
However this doesn't seem like working as I'm getting unexpected results which indicated the mocked object didn't return results as desired between two coroutines.
Does anyone have any ideas what went wrong with these code?

Verify that suspend function has not returned a value after simulating some time

I am trying to validate that a suspend function does not return anything at all in a certain test.
Consider the following situation:
val completionSignal = Channel<Unit>(capacity = 1, onBufferOverflow = BufferOverflow.DROP_LATEST)
suspend fun waitForCompletionSignal(): String {
completionSignal.receive()
return "Completion signal received"
}
I want to test this code with 2 unit tests, one that validates it returns the string when I provide the CompletionSignal with a value (thats the easy one).
And one that validates that it does not return anything when i don't give it anything. This is the hard one, since how long should I wait? And can i be sure the test fails if my code changes and suddenly the string is returned?
I got the following approach but I am missing some pieces:
#Test
fun `waitForCompletionSignal when completionSignal is provided assert result`() = runTest {
// Start waiting for result
val result = async { waitForCompletionSignal() }
// Provide completion signal
completionSignal.trySend(Unit)
// Await result and verify its correct
assertThat(result.await() == "Completion signal received")
}
#Test
fun `waitForCompletionSignal when completionSignal is not provided assert no result`() = runTest {
// Start waiting for result
val result = async { waitForCompletionSignal() }
// TODO?? some validation that succeeds if the test is just like this, but fails when i do the following:
completionSignal.trySend(Unit)
// A regular await would wait indefinately, and checking if the deferred result is completed does not work very well as well.
}
I hope the question is clear, thanks in advance.
I made an extension function on the deferred type to be able to wait for a max amount of time and after that it will return null. In my particular situation a delay time of 0 (so no delay whatsoever) is enough, but I can imagine that in some situations its useful to delay for a minimum amount of time.
#ExperimentalCoroutinesApi
suspend inline fun <reified T> Deferred<T>.awaitOrNull(
time: Long = 0,
crossinline actBlock: () -> Unit = { }
): T? = coroutineScope {
actBlock()
val timeoutJob = async<T?> {
delay(time)
null
}
return#coroutineScope select<T?> {
this#awaitOrNull.onAwait {
timeoutJob.cancel()
it
}
timeoutJob.onAwait {
this#awaitOrNull.cancel()
it
}
}
}
Using this method i can write the following tests that fail / succeed as expected:
// Succeeds
#Test
fun `waitForCompletionSignal when completionSignal is provided assert result`() = runTest {
val result = async {
waitForCompletionSignal()
}.awaitOrNull {
completionSignal.trySend(Unit)
}
assertThat(result == "Completion signal received")
}
// Succeeds
#Test
fun `waitForCompletionSignal when completionSignal is not provided assert no result`() = runTest {
val result = async {
waitForCompletionSignal()
}.awaitOrNull()
assertThat(result == null)
}
// Fails (to prove that it works)
#Test
fun `waitForCompletionSignal when completionSignal is not provided assert no result`() = runTest {
val result = async {
waitForCompletionSignal()
}.awaitOrNull {
completionSignal.trySend(Unit) // This (obviously) causes the test to fail, as I wanted.
}
assertThat(result == null)
}

Unit test with mockK - flatMap

I'm new in Unit Testing, I can't understand how to test this kind of method with kotlin, using MockK:
override fun register(firebaseId: String, uniqueId: String): Completable {
return Observable.just(0).observeOn(schedulerProvider.io()).flatMap {
val requestRegisterPushes = registerBuilder.build(firebaseId, uniqueId)
apiServiceFactory.build()
.registerPushes(requestRegisterPushes)
.subscribeOn(schedulerProvider.io())
.observeOn(schedulerProvider.ui())
}.flatMapCompletable {
Completable.complete()
}
}
This is my code for the test, the test was a success but the condition coverage does not increase.
#Test
fun `register_Test()`() {
val requestRegisterPushes = mockk<RequestRegisterPushes>(relaxed = true)
every { registerBuilder.build(any(), any(), any(), any()) } returns requestRegisterPushes
every { apiServiceFactory.build().register(requestRegisterPushes) } returns Observable.just(SimpleResponse())
val resp = userRepository.register("x7gbyb68837g78s", "XXX-XXX-XXX")
}
I would really appreciate it if you could help me a little.
Of course you don't have any coverage because code inside flatmap and flatMapCompletable operator was not executed.
You need to subscribe to Observable to make it emmit elements in you case it will emmit 0 only when you subscribe for it. That's how RxJava works. Something like this:
val subscriber = TestSubscriber<>();
val resp = userRepository.register("x7gbyb68837g78s", "XXX-XXX-XXX").subscribe(subscriber)
subscriber.assertComplete()

How can I use Mockito to test this function?

I'm trying to test that Permission.REVEAL_NOW returns the method isFeatureRevealNowAvailable.
Heres some code I already tried but didn't succeed with. Any help would be hugely appreciated as always!
Function to test:
class PermissionRepository(private val permissionApi: PermissionApi,
private val appPreferences: AppPreferences) {
fun checkPermission(permission: PermissionType, onPermissionResponse: (Boolean) -> Unit) {
Log.i("Permission", "Checking permission")
when (permission) {
PermissionType.REVEAL_NOW -> {
isFeatureRevealNowAvailable(onPermissionResponse, ::errorHandler)
}
}
}
Attempted solution:
#RunWith(MockitoJUnitRunner::class)
class PermissionRepositoryTest{
#Test
fun checkPermissionTest() {
val mockPermissionRepository = mock(PermissionRepository::class.java)
val mockPermissionApi = mock(PermissionApi::class.java)
val result = mockPermissionRepository.checkPermission(PermissionType.REVEAL_NOW, onPermissionResponse = null)
//Unsure of what to use here AssertThat or Mockito's "when" function
}
}
private fun isFeatureRevealNowAvailable(permissionResponseHandler: (Boolean) -> Unit, permissionError: (Throwable) -> Unit) {
permissionApi.getRevealNowPermission().enqueue(object : Callback<PermissionResponse> {
override fun onFailure(call: Call<PermissionResponse>, t: Throwable) {
permissionResponseHandler(false)
permissionError(t)
}
override fun onResponse(call: Call<PermissionResponse>, response: Response<PermissionResponse>) {
val permissionResult = response.body()?.isRevealNow ?: false
updateUserLocalPermission(PermissionType.REVEAL_NOW, permissionResult)
permissionResponseHandler(permissionResult)
}
})
}
(TL;DR - go to Example)
Since you don't define specifically what you want to test or achieve, I will give some overall tips:
Mocking
Never mock the class you want to test
val mockPermissionRepository = mock(PermissionRepository::class.java)
Mock only what you want to exclude from your test but rely on
Try to avoid mocks whenever it is possible and makes sence, because they simulate a perfect world, not the real behaviour
Test naming
Use proper names to describe what you want to achive with your test. My personal favourite is to start the sentence with the word "should ..."
Example
Two tests I could image to write for your function:
#Test
fun `should invoke reveal permission on PermissionApi when type is REVEAL_NOW`(){
val mockPermissionApi = mock(PermissionApi::class.java)
val permissionRepository = PermissionRepository(mockPermissionApi, mock())
permissionRepository.checkPermission(PermissionType.REVEAL_NOW, onPermissionResponse = {})
verify(mockPermissionApi, times(1)).getRevealNowPermission()
}
#Test
fun `should do nothing when type is not REVEAL_NOW`() {
val mockPermissionApi = mock(PermissionApi::class.java)
val permissionRepository = PermissionRepository(mockPermissionApi, mock())
permissionRepository.checkPermission(PermissionType.ELSE, onPermissionResponse = {})
verify(mockPermissionApi, times(0)).getRevealNowPermission()
}

What are the best practices for unit testing properties with code in the setter?

I'm fairly new to unit testing and we are actually attempting to use it on a project. There is a property like this.
public TimeSpan CountDown
{
get
{
return _countDown;
}
set
{
long fraction = value.Ticks % 10000000;
value -= TimeSpan.FromTicks(fraction);
if(fraction > 5000000)
value += TimeSpan.FromSeconds(1);
if(_countDown != value)
{
_countDown = value;
NotifyChanged("CountDown");
}
}
}
My test looks like this.
[TestMethod]
public void CountDownTest_GetSet_PropChangedShouldFire()
{
ManualRafflePresenter target = new ManualRafflePresenter();
bool fired = false;
string name = null;
target.PropertyChanged += new PropertyChangedEventHandler((o, a) =>
{
fired = true;
name = a.PropertyName;
});
TimeSpan expected = new TimeSpan(0, 1, 25);
TimeSpan actual;
target.CountDown = expected;
actual = target.CountDown;
Assert.AreEqual(expected, actual);
Assert.IsTrue(fired);
Assert.AreEqual("CountDown", name);
}
The question is how do I test the code in the setter? Do I break it out into a method? If I do it would probably be private since no one else needs to use this. But they say not to test private methods. Do make a class if this is the only case? would two uses of this code make a class worthwhile? What is wrong with this code from a design standpoint. What is correct?
The way you've got is fine (call the setter and then check the get returns the expected value).
Make sure you choose a selection of test values that exercise all the paths in that setter. A single set/get test isn't sufficient coverage.