From 34a003c68cb96b955306dd4ed0f6ae33f54e2c79 Mon Sep 17 00:00:00 2001 From: Jameson Williams Date: Tue, 10 Dec 2024 21:19:10 -0600 Subject: [PATCH] Migrate all remaining mockito tests to mockk. Resolves #13835 --- .../v2/ArchivedMediaObjectIteratorTest.kt | 26 +-- .../voice/VoiceNotePlayerCallbackTest.kt | 45 ++-- .../paged/ContactSearchPagedDataSourceTest.kt | 60 ++--- .../paged/SafetyNumberRepositoryTest.kt | 217 ++++++++++++------ .../ConversationUpdateTickTest.kt | 28 +-- .../storage/SignalBaseIdentityKeyStoreTest.kt | 28 ++- ...NewContextWithAppendedDeleteJoinRequest.kt | 36 ++- .../MockApplicationDependencyProvider.kt | 3 +- .../mediasend/MediaRepositoryTest.kt | 23 +- .../securesms/recipients/BaseRecipientTest.kt | 48 ---- .../recipients/Recipient_getChatColorsTest.kt | 21 +- 11 files changed, 272 insertions(+), 263 deletions(-) delete mode 100644 app/src/test/java/org/thoughtcrime/securesms/recipients/BaseRecipientTest.kt diff --git a/app/src/test/java/org/thoughtcrime/securesms/backup/v2/ArchivedMediaObjectIteratorTest.kt b/app/src/test/java/org/thoughtcrime/securesms/backup/v2/ArchivedMediaObjectIteratorTest.kt index c398c76876..92b2794abd 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/backup/v2/ArchivedMediaObjectIteratorTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/backup/v2/ArchivedMediaObjectIteratorTest.kt @@ -1,25 +1,19 @@ package org.thoughtcrime.securesms.backup.v2 -import org.junit.Before +import io.mockk.every +import io.mockk.mockk import org.junit.Test -import org.mockito.kotlin.any -import org.mockito.kotlin.mock -import org.mockito.kotlin.whenever import org.thoughtcrime.securesms.MockCursor import org.thoughtcrime.securesms.assertIsSize class ArchivedMediaObjectIteratorTest { - - private val cursor: MockCursor = mock() - - @Before - fun setUp() { - whenever(cursor.getString(any())).thenReturn("A") - whenever(cursor.moveToPosition(any())).thenCallRealMethod() - whenever(cursor.moveToNext()).thenCallRealMethod() - whenever(cursor.position).thenCallRealMethod() - whenever(cursor.isLast).thenCallRealMethod() - whenever(cursor.isAfterLast).thenCallRealMethod() + private val cursor = mockk(relaxed = true) { + every { getString(any()) } returns "A" + every { moveToPosition(any()) } answers { callOriginal() } + every { moveToNext() } answers { callOriginal() } + every { position } answers { callOriginal() } + every { isLast } answers { callOriginal() } + every { isAfterLast } answers { callOriginal() } } @Test @@ -33,7 +27,7 @@ class ArchivedMediaObjectIteratorTest { } private fun runTest(size: Int) { - whenever(cursor.count).thenReturn(size) + every { cursor.count } returns size val iterator = ArchivedMediaObjectIterator(cursor) val list = iterator.asSequence().toList() diff --git a/app/src/test/java/org/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallbackTest.kt b/app/src/test/java/org/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallbackTest.kt index 72e9c5fc9d..7b740fd8f5 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallbackTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/components/voice/VoiceNotePlayerCallbackTest.kt @@ -9,34 +9,29 @@ import androidx.media3.common.C import androidx.media3.session.MediaSession import androidx.media3.session.SessionCommand import androidx.test.core.app.ApplicationProvider +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito -import org.mockito.Mockito.anyBoolean -import org.mockito.Mockito.mock -import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` -import org.mockito.kotlin.any -import org.mockito.kotlin.eq import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config @RunWith(RobolectricTestRunner::class) @Config(manifest = Config.NONE, application = Application::class) class VoiceNotePlayerCallbackTest { - private val context: Context = ApplicationProvider.getApplicationContext() private val mediaAudioAttributes = AudioAttributes.Builder().setContentType(C.AUDIO_CONTENT_TYPE_MUSIC).setUsage(C.USAGE_MEDIA).build() private val callAudioAttributes = AudioAttributes.Builder().setContentType(C.AUDIO_CONTENT_TYPE_SPEECH).setUsage(C.USAGE_VOICE_COMMUNICATION).build() - private val session = mock(MediaSession::class.java) - private val controllerInfo = mock(MediaSession.ControllerInfo::class.java) - private val player: VoiceNotePlayer = mock(VoiceNotePlayer::class.java) + private val session = mockk() + private val controllerInfo = mockk() + private val player = mockk(relaxUnitFun = true) private val testSubject = VoiceNotePlayerCallback(context, player) @Test fun `Given stream is media, When I onCommand for voice, then I expect the stream to switch to voice and continue playback`() { // GIVEN - `when`(player.audioAttributes).thenReturn(mediaAudioAttributes) + every { player.audioAttributes } returns mediaAudioAttributes val command = SessionCommand(VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM, Bundle.EMPTY) val extras = Bundle().apply { putInt(VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM, AudioManager.STREAM_VOICE_CALL) } @@ -46,15 +41,15 @@ class VoiceNotePlayerCallbackTest { testSubject.onCustomCommand(session, controllerInfo, command, extras) // THEN - verify(player).playWhenReady = false - verify(player).setAudioAttributes(expected, false) - verify(player).playWhenReady = true + verify { player.playWhenReady = false } + verify { player.setAudioAttributes(expected, false) } + verify { player.playWhenReady = true } } @Test fun `Given stream is voice, When I onCommand for media, then I expect the stream to switch to media and pause playback`() { // GIVEN - `when`(player.audioAttributes).thenReturn(callAudioAttributes) + every { player.audioAttributes } returns callAudioAttributes val command = SessionCommand(VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM, Bundle.EMPTY) val extras = Bundle().apply { putInt(VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM, AudioManager.STREAM_MUSIC) } @@ -64,15 +59,15 @@ class VoiceNotePlayerCallbackTest { testSubject.onCustomCommand(session, controllerInfo, command, extras) // THEN - verify(player).playWhenReady = false - verify(player).setAudioAttributes(expected, true) - verify(player, Mockito.never()).playWhenReady = true + verify { player.playWhenReady = false } + verify { player.setAudioAttributes(expected, true) } + verify(exactly = 0) { player.playWhenReady = true } } @Test fun `Given stream is voice, When I onCommand for voice, then I expect no change`() { // GIVEN - `when`(player.audioAttributes).thenReturn(callAudioAttributes) + every { player.audioAttributes } returns callAudioAttributes val command = SessionCommand(VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM, Bundle.EMPTY) val extras = Bundle().apply { putInt(VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM, AudioManager.STREAM_VOICE_CALL) } @@ -81,14 +76,14 @@ class VoiceNotePlayerCallbackTest { testSubject.onCustomCommand(session, controllerInfo, command, extras) // THEN - verify(player, Mockito.never()).playWhenReady = anyBoolean() - verify(player, Mockito.never()).setAudioAttributes(any(), eq(false)) + verify(exactly = 0) { player.playWhenReady = any() } + verify(exactly = 0) { player.setAudioAttributes(any(), false) } } @Test fun `Given stream is media, When I onCommand for media, then I expect no change`() { // GIVEN - `when`(player.audioAttributes).thenReturn(mediaAudioAttributes) + every { player.audioAttributes } returns mediaAudioAttributes val command = SessionCommand(VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM, Bundle.EMPTY) val extras = Bundle().apply { putInt(VoiceNotePlaybackService.ACTION_SET_AUDIO_STREAM, AudioManager.STREAM_MUSIC) } @@ -97,7 +92,7 @@ class VoiceNotePlayerCallbackTest { testSubject.onCustomCommand(session, controllerInfo, command, extras) // THEN - verify(player, Mockito.never()).playWhenReady = anyBoolean() - verify(player, Mockito.never()).setAudioAttributes(any(), anyBoolean()) + verify(exactly = 0) { player.playWhenReady = any() } + verify(exactly = 0) { player.setAudioAttributes(any(), any()) } } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceTest.kt b/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceTest.kt index 8ba04e8953..e39fcbf405 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceTest.kt @@ -2,20 +2,19 @@ package org.thoughtcrime.securesms.contacts.paged import android.app.Application import androidx.core.os.bundleOf +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic import org.junit.Assert import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith -import org.mockito.kotlin.any -import org.mockito.kotlin.anyOrNull -import org.mockito.kotlin.isNull -import org.mockito.kotlin.mock -import org.mockito.kotlin.whenever import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.thoughtcrime.securesms.MockCursor import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode +import org.thoughtcrime.securesms.dependencies.AppDependencies +import org.thoughtcrime.securesms.recipients.LiveRecipientCache import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel @@ -23,26 +22,28 @@ import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel @RunWith(RobolectricTestRunner::class) @Config(application = Application::class) class ContactSearchPagedDataSourceTest { - - private val repository: ContactSearchPagedDataSourceRepository = mock() - private val cursor: MockCursor = mock() + private val repository = mockk(relaxed = true) + private val cursor = mockk(relaxed = true) private val groupStoryData = ContactSearchData.Story(Recipient.UNKNOWN, 0, DistributionListPrivacyMode.ALL) @Before fun setUp() { - whenever(repository.getRecipientFromGroupRecord(any())).thenReturn(Recipient.UNKNOWN) - whenever(repository.getRecipientFromSearchCursor(any())).thenReturn(Recipient.UNKNOWN) - whenever(repository.getRecipientFromThreadCursor(cursor)).thenReturn(Recipient.UNKNOWN) - whenever(repository.getRecipientFromDistributionListCursor(cursor)).thenReturn(Recipient.UNKNOWN) - whenever(repository.getPrivacyModeFromDistributionListCursor(cursor)).thenReturn(DistributionListPrivacyMode.ALL) - whenever(repository.getGroupStories()).thenReturn(emptySet()) - whenever(repository.getLatestStorySends(any())).thenReturn(emptyList()) - whenever(cursor.getString(any())).thenReturn("A") - whenever(cursor.moveToPosition(any())).thenCallRealMethod() - whenever(cursor.moveToNext()).thenCallRealMethod() - whenever(cursor.position).thenCallRealMethod() - whenever(cursor.isLast).thenCallRealMethod() - whenever(cursor.isAfterLast).thenCallRealMethod() + mockkStatic(AppDependencies::class) + every { AppDependencies.recipientCache } returns mockk(relaxed = true) + + every { repository.getRecipientFromGroupRecord(any()) } returns Recipient.UNKNOWN + every { repository.getRecipientFromSearchCursor(any()) } returns Recipient.UNKNOWN + every { repository.getRecipientFromThreadCursor(cursor) } returns Recipient.UNKNOWN + every { repository.getRecipientFromDistributionListCursor(cursor) } returns Recipient.UNKNOWN + every { repository.getPrivacyModeFromDistributionListCursor(cursor) } returns DistributionListPrivacyMode.ALL + every { repository.getGroupStories() } returns emptySet() + every { repository.getLatestStorySends(any()) } returns emptyList() + every { cursor.getString(any()) } returns "A" + every { cursor.moveToPosition(any()) } answers { callOriginal() } + every { cursor.moveToNext() } answers { callOriginal() } + every { cursor.position } answers { callOriginal() } + every { cursor.isLast } answers { callOriginal() } + every { cursor.isAfterLast } answers { callOriginal() } } @Test @@ -99,7 +100,6 @@ class ContactSearchPagedDataSourceTest { Assert.assertEquals(expected, resultKeys) } - @Ignore @Test fun `Given storiesWithHeaderAndExtras, when I load 11, then I expect properly structured output`() { val testSubject = createStoriesSubject() @@ -176,9 +176,9 @@ class ContactSearchPagedDataSourceTest { ) } - whenever(repository.getStories(anyOrNull())).thenReturn(cursor) - whenever(repository.recipientNameContainsQuery(Recipient.UNKNOWN, null)).thenReturn(true) - whenever(cursor.count).thenReturn(10) + every { repository.getStories(any()) } returns cursor + every { repository.recipientNameContainsQuery(Recipient.UNKNOWN, null) } returns true + every { cursor.count } returns 10 return ContactSearchPagedDataSource(configuration, repository) } @@ -201,10 +201,10 @@ class ContactSearchPagedDataSourceTest { ) } - whenever(repository.getRecents(recents)).thenReturn(cursor) - whenever(repository.queryNonGroupContacts(isNull(), any())).thenReturn(cursor) - whenever(repository.querySignalContacts(any())).thenReturn(cursor) - whenever(cursor.count).thenReturn(10) + every { repository.getRecents(recents) } returns cursor + every { repository.queryNonGroupContacts(isNull(), any()) } returns cursor + every { repository.querySignalContacts(any()) } returns cursor + every { cursor.count } returns 10 return ContactSearchPagedDataSource(configuration, repository) } diff --git a/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepositoryTest.kt b/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepositoryTest.kt index 8cd579e499..91016512a1 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepositoryTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepositoryTest.kt @@ -1,24 +1,17 @@ package org.thoughtcrime.securesms.contacts.paged import android.app.Application +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkObject +import io.mockk.mockkStatic +import io.mockk.verify import io.reactivex.rxjava3.core.Single import org.junit.Before import org.junit.BeforeClass -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.MockedStatic -import org.mockito.internal.configuration.plugins.Plugins -import org.mockito.internal.junit.JUnitRule -import org.mockito.junit.MockitoRule -import org.mockito.kotlin.any -import org.mockito.kotlin.argThat -import org.mockito.kotlin.times -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever -import org.mockito.quality.Strictness import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.signal.core.util.logging.Log @@ -29,6 +22,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabaseTestUtils import org.thoughtcrime.securesms.database.model.IdentityRecord import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId +import org.thoughtcrime.securesms.testutil.MockAppDependenciesRule import org.thoughtcrime.securesms.testutil.SystemOutLogger import org.thoughtcrime.securesms.util.IdentityUtil import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException @@ -39,26 +33,14 @@ import java.io.IOException import java.util.Optional import java.util.concurrent.TimeUnit -@Ignore @RunWith(RobolectricTestRunner::class) @Config(application = Application::class) class SafetyNumberRepositoryTest { + @get:Rule + val appDependencies = MockAppDependenciesRule() - @Rule - @JvmField - val mockitoRule: MockitoRule = JUnitRule(Plugins.getMockitoLogger(), Strictness.STRICT_STUBS) - - @Mock - lateinit var profileService: ProfileService - - @Mock(lenient = true) - lateinit var aciIdentityStore: SignalIdentityKeyStore - - @Mock - lateinit var staticIdentityUtil: MockedStatic - - @Mock - lateinit var staticRecipient: MockedStatic + private val profileService = mockk() + private val aciIdentityStore = mockk() private var now: Long = System.currentTimeMillis() @@ -77,6 +59,11 @@ class SafetyNumberRepositoryTest { @Before fun setUp() { + mockkStatic(IdentityUtil::class) + + mockkObject(Recipient) + mockkStatic(Recipient::class) + now = System.currentTimeMillis() repository = SafetyNumberRepository(profileService, aciIdentityStore) @@ -85,7 +72,7 @@ class SafetyNumberRepositoryTest { for (id in 1L until 12) { val recipient = RecipientDatabaseTestUtils.createRecipient(resolved = true, recipientId = RecipientId.from(id)) - staticRecipient.`when` { Recipient.resolved(RecipientId.from(id)) }.thenReturn(recipient) + every { Recipient.resolved(RecipientId.from(id)) } returns recipient recipientPool.add(recipient) val record = IdentityRecord( @@ -96,11 +83,11 @@ class SafetyNumberRepositoryTest { timestamp = 0, nonblockingApproval = false ) - whenever(aciIdentityStore.getIdentityRecord(recipient.id)).thenReturn(Optional.of(record)) + every { aciIdentityStore.getIdentityRecord(recipient.id) } returns Optional.of(record) identityPool[recipient] = record } - staticRecipient.`when` { Recipient.self() }.thenReturn(recipientPool[0]) + every { Recipient.self() } returns recipientPool[0] } /** @@ -111,13 +98,33 @@ class SafetyNumberRepositoryTest { val other = recipientPool[1] val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false)) - staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other)) - whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey))) - .thenReturn(Single.just(ServiceResponse.forResult(IdentityCheckResponse(listOf()), 200, ""))) + every { + Recipient.resolvedList( + match { list -> + list.containsAll( + keys.map { key -> + key.recipientId + } + ) + } + ) + } returns listOf(other) + + every { + profileService.performIdentityCheck( + mapOf(other.requireServiceId() to identityPool[other]!!.identityKey) + ) + } returns Single.just( + ServiceResponse.forResult( + IdentityCheckResponse(listOf()), + 200, + "" + ) + ) repository.batchSafetyNumberCheckSync(keys, now) - staticIdentityUtil.verifyNoInteractions() + verify(exactly = 0) { IdentityUtil.saveIdentity(any(), any()) } } /** @@ -130,14 +137,27 @@ class SafetyNumberRepositoryTest { val otherNewIdentityKey = IdentityKeyUtil.generateIdentityKeyPair().publicKey val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false)) - staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other)) - whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey))) - .thenReturn(Single.just(ServiceResponse.forResult(IdentityCheckResponse(listOf(IdentityCheckResponse.ServiceIdentityPair(otherAci, otherNewIdentityKey))), 200, ""))) + every { + Recipient.resolvedList(match { list -> list.containsAll(keys.map { key -> key.recipientId }) }) + } returns listOf(other) + + every { + profileService.performIdentityCheck( + mapOf(other.requireServiceId() to identityPool[other]!!.identityKey) + ) + } returns Single.just( + ServiceResponse.forResult( + IdentityCheckResponse( + listOf(IdentityCheckResponse.ServiceIdentityPair(otherAci, otherNewIdentityKey)) + ), + 200, + "" + ) + ) repository.batchSafetyNumberCheckSync(keys, now) - staticIdentityUtil.verify { IdentityUtil.saveIdentity(otherAci.toString(), otherNewIdentityKey) } - staticIdentityUtil.verifyNoMoreInteractions() + verify { IdentityUtil.saveIdentity(otherAci.toString(), otherNewIdentityKey) } } /** @@ -151,14 +171,30 @@ class SafetyNumberRepositoryTest { val otherNewIdentityKey = IdentityKeyUtil.generateIdentityKeyPair().publicKey val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false), ContactSearchKey.RecipientSearchKey(secondOther.id, false)) - staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other, secondOther)) - whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey, secondOther.requireServiceId() to identityPool[secondOther]!!.identityKey))) - .thenReturn(Single.just(ServiceResponse.forResult(IdentityCheckResponse(listOf(IdentityCheckResponse.ServiceIdentityPair(otherAci, otherNewIdentityKey))), 200, ""))) + every { + Recipient.resolvedList(match { list -> list.containsAll(keys.map { key -> key.recipientId }) }) + } returns listOf(other, secondOther) + + every { + profileService.performIdentityCheck( + mapOf( + other.requireServiceId() to identityPool[other]!!.identityKey, + secondOther.requireServiceId() to identityPool[secondOther]!!.identityKey + ) + ) + } returns Single.just( + ServiceResponse.forResult( + IdentityCheckResponse( + listOf(IdentityCheckResponse.ServiceIdentityPair(otherAci, otherNewIdentityKey)) + ), + 200, + "" + ) + ) repository.batchSafetyNumberCheckSync(keys, now) - staticIdentityUtil.verify { IdentityUtil.saveIdentity(otherAci.toString(), otherNewIdentityKey) } - staticIdentityUtil.verifyNoMoreInteractions() + verify { IdentityUtil.saveIdentity(otherAci.toString(), otherNewIdentityKey) } } /** @@ -169,18 +205,24 @@ class SafetyNumberRepositoryTest { val other = recipientPool[1] val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false)) - staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other)) - whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey))) - .thenReturn(Single.just(ServiceResponse.forResult(IdentityCheckResponse(listOf()), 200, ""))) + every { + Recipient.resolvedList(match { list -> list.containsAll(keys.map { key -> key.recipientId }) }) + } returns listOf(other) + + every { + profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey)) + } returns Single.just(ServiceResponse.forResult(IdentityCheckResponse(listOf()), 200, "")) repository.batchSafetyNumberCheckSync(keys, now) - verify(profileService, times(1)).performIdentityCheck(any()) - repository.batchSafetyNumberCheckSync(keys, now + TimeUnit.SECONDS.toMillis(10)) - verify(profileService, times(1)).performIdentityCheck(any()) - repository.batchSafetyNumberCheckSync(keys, now + TimeUnit.SECONDS.toMillis(31)) - verify(profileService, times(2)).performIdentityCheck(any()) + verify(exactly = 1) { profileService.performIdentityCheck(any()) } - staticIdentityUtil.verifyNoInteractions() + repository.batchSafetyNumberCheckSync(keys, now + TimeUnit.SECONDS.toMillis(10)) + verify(exactly = 1) { profileService.performIdentityCheck(any()) } + + repository.batchSafetyNumberCheckSync(keys, now + TimeUnit.SECONDS.toMillis(31)) + verify(exactly = 2) { profileService.performIdentityCheck(any()) } + + verify(exactly = 0) { IdentityUtil.saveIdentity(any(), any()) } } /** @@ -188,19 +230,22 @@ class SafetyNumberRepositoryTest { */ @Test fun batchSafetyNumberCheckSync_batchOf10WithSmallBatchSize_noChanges() { - val keys = recipientPool.map { ContactSearchKey.RecipientSearchKey(it.id, false) } + val keys = recipientPool.map { receipient -> ContactSearchKey.RecipientSearchKey(receipient.id, false) } val others = recipientPool.subList(1, recipientPool.lastIndex) - staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(others.map { it.id }) }) }.thenReturn(others) + every { + Recipient.resolvedList(match { list -> list.containsAll(others.map { key -> key.id }) }) + } returns others - for (chunk in others.chunked(2)) { - whenever(profileService.performIdentityCheck(chunk.associate { it.requireServiceId() to identityPool[it]!!.identityKey })) - .thenReturn(Single.just(ServiceResponse.forResult(IdentityCheckResponse(listOf()), 200, ""))) + every { + profileService.performIdentityCheck(any()) + } answers { + Single.just(ServiceResponse.forResult(IdentityCheckResponse(listOf()), 200, "")) } repository.batchSafetyNumberCheckSync(keys, now, 2) - staticIdentityUtil.verifyNoInteractions() + verify(exactly = 0) { IdentityUtil.saveIdentity(any(), any()) } } @Test @@ -208,13 +253,21 @@ class SafetyNumberRepositoryTest { val other = recipientPool[1] val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false)) - staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other)) - whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey))) - .thenReturn(Single.just(ServiceResponse.forApplicationError(NonSuccessfulResponseCodeException(400), 400, ""))) + every { + Recipient.resolvedList(match { list -> list.containsAll(keys.map { key -> key.recipientId }) }) + } returns listOf(other) + + every { + profileService.performIdentityCheck( + mapOf(other.requireServiceId() to identityPool[other]!!.identityKey) + ) + } returns Single.just( + ServiceResponse.forApplicationError(NonSuccessfulResponseCodeException(400), 400, "") + ) repository.batchSafetyNumberCheckSync(keys, now) - staticIdentityUtil.verifyNoInteractions() + verify(exactly = 0) { IdentityUtil.saveIdentity(any(), any()) } } @Test @@ -222,13 +275,21 @@ class SafetyNumberRepositoryTest { val other = recipientPool[1] val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false)) - staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other)) - whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey))) - .thenReturn(Single.just(ServiceResponse.forUnknownError(IOException()))) + every { + Recipient.resolvedList(match { list -> list.containsAll(keys.map { key -> key.recipientId }) }) + } returns listOf(other) + + every { + profileService.performIdentityCheck( + mapOf(other.requireServiceId() to identityPool[other]!!.identityKey) + ) + } returns Single.just( + ServiceResponse.forUnknownError(IOException()) + ) repository.batchSafetyNumberCheckSync(keys, now) - staticIdentityUtil.verifyNoInteractions() + verify(exactly = 0) { IdentityUtil.saveIdentity(any(), any()) } } @Test @@ -236,12 +297,24 @@ class SafetyNumberRepositoryTest { val other = recipientPool[1] val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false)) - staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other)) - whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey))) - .thenReturn(Single.just(ServiceResponse.forResult(IdentityCheckResponse(), 200, ""))) + every { + Recipient.resolvedList(match { list -> list.containsAll(keys.map { key -> key.recipientId }) }) + } returns listOf(other) + + every { + profileService.performIdentityCheck( + mapOf(other.requireServiceId() to identityPool[other]!!.identityKey) + ) + } returns Single.just( + ServiceResponse.forResult( + IdentityCheckResponse(), + 200, + "" + ) + ) repository.batchSafetyNumberCheckSync(keys, now) - staticIdentityUtil.verifyNoInteractions() + verify(exactly = 0) { IdentityUtil.saveIdentity(any(), any()) } } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/conversation/ConversationUpdateTickTest.kt b/app/src/test/java/org/thoughtcrime/securesms/conversation/ConversationUpdateTickTest.kt index 6dea15735a..d2e1c29f28 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/conversation/ConversationUpdateTickTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/conversation/ConversationUpdateTickTest.kt @@ -2,12 +2,13 @@ package org.thoughtcrime.securesms.conversation import android.app.Application import androidx.lifecycle.LifecycleOwner +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import io.mockk.runs +import io.mockk.verify import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.mock -import org.mockito.Mockito.never -import org.mockito.Mockito.times -import org.mockito.Mockito.verify import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.robolectric.shadows.ShadowLooper @@ -16,9 +17,10 @@ import java.util.concurrent.TimeUnit @RunWith(RobolectricTestRunner::class) @Config(manifest = Config.NONE, application = Application::class) class ConversationUpdateTickTest { - - private val lifecycleOwner = mock(LifecycleOwner::class.java) - private val listener = mock(ConversationUpdateTick.OnTickListener::class.java) + private val lifecycleOwner = mockk() + private val listener = mockk { + every { onTick() } just runs + } private val testSubject = ConversationUpdateTick(listener) private val timeoutMillis = ConversationUpdateTick.TIMEOUT @@ -26,7 +28,7 @@ class ConversationUpdateTickTest { @Test fun `Given onResume not invoked, then I expect zero invocations of onTick`() { // THEN - verify(listener, never()).onTick() + verify(exactly = 0) { listener.onTick() } } @Test @@ -36,7 +38,7 @@ class ConversationUpdateTickTest { testSubject.onResume(lifecycleOwner) // THEN - verify(listener, never()).onTick() + verify(exactly = 0) { listener.onTick() } } @Test @@ -46,7 +48,7 @@ class ConversationUpdateTickTest { ShadowLooper.idleMainLooper(timeoutMillis / 2, TimeUnit.MILLISECONDS) // THEN - verify(listener, never()).onTick() + verify(exactly = 0) { listener.onTick() } } @Test @@ -58,7 +60,7 @@ class ConversationUpdateTickTest { ShadowLooper.idleMainLooper(timeoutMillis, TimeUnit.MILLISECONDS) // THEN - verify(listener, times(1)).onTick() + verify(exactly = 1) { listener.onTick() } } @Test @@ -70,7 +72,7 @@ class ConversationUpdateTickTest { ShadowLooper.idleMainLooper(timeoutMillis * 5, TimeUnit.MILLISECONDS) // THEN - verify(listener, times(5)).onTick() + verify(exactly = 5) { listener.onTick() } } @Test @@ -83,6 +85,6 @@ class ConversationUpdateTickTest { ShadowLooper.idleMainLooper(timeoutMillis, TimeUnit.MILLISECONDS) // THEN - verify(listener, never()).onTick() + verify(exactly = 0) { listener.onTick() } } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/crypto/storage/SignalBaseIdentityKeyStoreTest.kt b/app/src/test/java/org/thoughtcrime/securesms/crypto/storage/SignalBaseIdentityKeyStoreTest.kt index 91be428c2a..aa7de17968 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/crypto/storage/SignalBaseIdentityKeyStoreTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/crypto/storage/SignalBaseIdentityKeyStoreTest.kt @@ -1,13 +1,12 @@ package org.thoughtcrime.securesms.crypto.storage import android.content.Context +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test -import org.mockito.Mockito.mock -import org.mockito.Mockito.times -import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` import org.signal.libsignal.protocol.IdentityKey import org.signal.libsignal.protocol.SignalProtocolAddress import org.signal.libsignal.protocol.ecc.ECPublicKey @@ -16,7 +15,6 @@ import org.thoughtcrime.securesms.database.model.IdentityStoreRecord import org.whispersystems.signalservice.test.LibSignalLibraryUtil.assumeLibSignalSupportedOnOS class SignalBaseIdentityKeyStoreTest { - companion object { private const val ADDRESS = "address1" } @@ -28,36 +26,36 @@ class SignalBaseIdentityKeyStoreTest { @Test fun `getIdentity() hits disk on first retrieve but not the second`() { - val mockDb = mock(IdentityTable::class.java) - val subject = SignalBaseIdentityKeyStore(mock(Context::class.java), mockDb) + val mockDb = mockk() + val subject = SignalBaseIdentityKeyStore(mockk(), mockDb) val identityKey = IdentityKey(ECPublicKey.fromPublicKeyBytes(ByteArray(32))) val record = mockRecord(ADDRESS, identityKey) - `when`(mockDb.getIdentityStoreRecord(ADDRESS)).thenReturn(record) + every { mockDb.getIdentityStoreRecord(ADDRESS) } returns record assertEquals(identityKey, subject.getIdentity(SignalProtocolAddress(ADDRESS, 1))) - verify(mockDb, times(1)).getIdentityStoreRecord(ADDRESS) + verify(exactly = 1) { mockDb.getIdentityStoreRecord(ADDRESS) } assertEquals(identityKey, subject.getIdentity(SignalProtocolAddress(ADDRESS, 1))) - verify(mockDb, times(1)).getIdentityStoreRecord(ADDRESS) + verify(exactly = 1) { mockDb.getIdentityStoreRecord(ADDRESS) } } @Test fun `invalidate() evicts cache entry`() { - val mockDb = mock(IdentityTable::class.java) - val subject = SignalBaseIdentityKeyStore(mock(Context::class.java), mockDb) + val mockDb = mockk() + val subject = SignalBaseIdentityKeyStore(mockk(), mockDb) val identityKey = IdentityKey(ECPublicKey.fromPublicKeyBytes(ByteArray(32))) val record = mockRecord(ADDRESS, identityKey) - `when`(mockDb.getIdentityStoreRecord(ADDRESS)).thenReturn(record) + every { mockDb.getIdentityStoreRecord(ADDRESS) } returns record assertEquals(identityKey, subject.getIdentity(SignalProtocolAddress(ADDRESS, 1))) - verify(mockDb, times(1)).getIdentityStoreRecord(ADDRESS) + verify(exactly = 1) { mockDb.getIdentityStoreRecord(ADDRESS) } subject.invalidate(ADDRESS) assertEquals(identityKey, subject.getIdentity(SignalProtocolAddress(ADDRESS, 1))) - verify(mockDb, times(2)).getIdentityStoreRecord(ADDRESS) + verify(exactly = 2) { mockDb.getIdentityStoreRecord(ADDRESS) } } private fun mockRecord(addressName: String, identityKey: IdentityKey): IdentityStoreRecord { diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/model/MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest.kt b/app/src/test/java/org/thoughtcrime/securesms/database/model/MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest.kt index 08c2e52b51..f15a8edabf 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/model/MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/model/MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest.kt @@ -1,30 +1,28 @@ package org.thoughtcrime.securesms.database.model +import io.mockk.every +import io.mockk.mockk import okio.ByteString import okio.ByteString.Companion.toByteString -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.`is` +import org.junit.Assert.assertEquals import org.junit.Test -import org.mockito.kotlin.doReturn -import org.mockito.kotlin.mock import org.signal.core.util.Base64 import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context import org.thoughtcrime.securesms.groups.v2.ChangeBuilder import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.internal.push.GroupContextV2 -import java.util.Random import java.util.UUID +import kotlin.random.Random @Suppress("ClassName") class MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest { - /** * Given a non-gv2 message, when I append, then I expect an assertion error */ @Test(expected = AssertionError::class) fun throwOnNonGv2() { - val messageRecord = mock { - on { decryptedGroupV2Context } doReturn null + val messageRecord = mockk { + every { decryptedGroupV2Context } returns null } MessageRecord.createNewContextWithAppendedDeleteJoinRequest(messageRecord, 0, ByteString.EMPTY) @@ -37,8 +35,8 @@ class MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest { fun throwOnEmptyGv2Change() { val groupContext = DecryptedGroupV2Context() - val messageRecord = mock { - on { decryptedGroupV2Context } doReturn groupContext + val messageRecord = mockk { + every { decryptedGroupV2Context } returns groupContext } MessageRecord.createNewContextWithAppendedDeleteJoinRequest(messageRecord, 0, ByteString.EMPTY) @@ -59,26 +57,20 @@ class MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest { .build() val context = DecryptedGroupV2Context.Builder() - .context(GroupContextV2.Builder().masterKey(randomBytes().toByteString()).build()) + .context(GroupContextV2.Builder().masterKey(Random.nextBytes(32).toByteString()).build()) .change(change) .build() - val messageRecord = mock { - on { decryptedGroupV2Context } doReturn context + val messageRecord = mockk { + every { decryptedGroupV2Context } returns context } val newEncodedBody = MessageRecord.createNewContextWithAppendedDeleteJoinRequest(messageRecord, 10, aliceByteString) val newContext = DecryptedGroupV2Context.ADAPTER.decode(Base64.decode(newEncodedBody)) - assertThat("revision updated to 10", newContext.change!!.revision, `is`(10)) - assertThat("change should retain join request", newContext.change!!.newRequestingMembers[0].aciBytes, `is`(aliceByteString)) - assertThat("change should add delete request", newContext.change!!.deleteRequestingMembers[0], `is`(aliceByteString)) - } - - private fun randomBytes(): ByteArray { - val bytes = ByteArray(32) - Random().nextBytes(bytes) - return bytes + assertEquals("revision updated to 10", newContext.change?.revision, 10) + assertEquals("change should retain join request", newContext.change?.newRequestingMembers?.single()?.aciBytes, aliceByteString) + assertEquals("change should add delete request", newContext.change?.deleteRequestingMembers?.single(), aliceByteString) } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/dependencies/MockApplicationDependencyProvider.kt b/app/src/test/java/org/thoughtcrime/securesms/dependencies/MockApplicationDependencyProvider.kt index 5e51598d97..78c32085aa 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/dependencies/MockApplicationDependencyProvider.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/dependencies/MockApplicationDependencyProvider.kt @@ -1,7 +1,6 @@ package org.thoughtcrime.securesms.dependencies import io.mockk.mockk -import org.mockito.Mockito import org.signal.core.util.billing.BillingApi import org.signal.core.util.concurrent.DeadlockDetector import org.signal.libsignal.net.Network @@ -134,7 +133,7 @@ class MockApplicationDependencyProvider : AppDependencies.Provider { } override fun provideDatabaseObserver(): DatabaseObserver { - return Mockito.mock(DatabaseObserver::class.java) + return mockk(relaxed = true) } override fun providePayments(signalServiceAccountManager: SignalServiceAccountManager): Payments { diff --git a/app/src/test/java/org/thoughtcrime/securesms/mediasend/MediaRepositoryTest.kt b/app/src/test/java/org/thoughtcrime/securesms/mediasend/MediaRepositoryTest.kt index b3d7cf1e6d..ffd5785b70 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/mediasend/MediaRepositoryTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/mediasend/MediaRepositoryTest.kt @@ -4,17 +4,12 @@ import android.app.Application import android.content.Context import android.net.Uri import androidx.test.core.app.ApplicationProvider +import io.mockk.every +import io.mockk.mockkStatic import org.junit.Assert.assertEquals import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers -import org.mockito.Mock -import org.mockito.MockedStatic -import org.mockito.Mockito.`when` -import org.mockito.junit.MockitoJUnit -import org.mockito.junit.MockitoRule import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.signal.core.util.logging.Log @@ -26,14 +21,6 @@ import java.util.Optional @RunWith(RobolectricTestRunner::class) @Config(manifest = Config.NONE, application = Application::class) class MediaRepositoryTest { - - @Rule - @JvmField - val mockitoRule: MockitoRule = MockitoJUnit.rule() - - @Mock - private lateinit var staticMediaUtilMock: MockedStatic - private lateinit var context: Context @Before @@ -41,7 +28,9 @@ class MediaRepositoryTest { Log.initialize(EmptyLogger()) context = ApplicationProvider.getApplicationContext() - `when`(MediaUtil.isOctetStream(MediaUtil.OCTET)).thenReturn(true) + + mockkStatic(MediaUtil::class) + every { MediaUtil.isOctetStream(MediaUtil.OCTET) } returns true } @Test @@ -62,7 +51,7 @@ class MediaRepositoryTest { val media = buildMedia(mimeType = MediaUtil.OCTET) // WHEN - `when`(MediaUtil.getMimeType(ArgumentMatchers.any(), ArgumentMatchers.any())).thenReturn(MediaUtil.IMAGE_JPEG) + every { MediaUtil.getMimeType(any(), any()) } returns MediaUtil.IMAGE_JPEG val result: Media = MediaRepository.fixMimeType(context, media) // THEN diff --git a/app/src/test/java/org/thoughtcrime/securesms/recipients/BaseRecipientTest.kt b/app/src/test/java/org/thoughtcrime/securesms/recipients/BaseRecipientTest.kt deleted file mode 100644 index c502fdd075..0000000000 --- a/app/src/test/java/org/thoughtcrime/securesms/recipients/BaseRecipientTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -package org.thoughtcrime.securesms.recipients - -import android.app.Application -import androidx.test.core.app.ApplicationProvider -import org.junit.Before -import org.junit.Rule -import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers -import org.mockito.Mock -import org.mockito.MockedConstruction -import org.mockito.MockedStatic -import org.mockito.Mockito.`when` -import org.mockito.junit.MockitoJUnit -import org.mockito.junit.MockitoRule -import org.robolectric.RobolectricTestRunner -import org.robolectric.annotation.Config -import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider -import org.thoughtcrime.securesms.dependencies.AppDependencies -import org.thoughtcrime.securesms.keyvalue.SignalStore - -@RunWith(RobolectricTestRunner::class) -@Config(manifest = Config.NONE, application = Application::class) -abstract class BaseRecipientTest { - - @Rule - @JvmField - val mockitoRule: MockitoRule = MockitoJUnit.rule() - - @Mock - private lateinit var applicationDependenciesStaticMock: MockedStatic - - @Mock - private lateinit var attachmentSecretProviderStaticMock: MockedStatic - - @Mock - private lateinit var signalStoreStaticMock: MockedStatic - - @Mock - private lateinit var mockedSignalStoreConstruction: MockedConstruction - - @Before - fun superSetUp() { - val application = ApplicationProvider.getApplicationContext() - - `when`(AppDependencies.application).thenReturn(application) - `when`(AttachmentSecretProvider.getInstance(ArgumentMatchers.any())).thenThrow(RuntimeException::class.java) - } -} diff --git a/app/src/test/java/org/thoughtcrime/securesms/recipients/Recipient_getChatColorsTest.kt b/app/src/test/java/org/thoughtcrime/securesms/recipients/Recipient_getChatColorsTest.kt index 09e7f33786..c45e9d6496 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/recipients/Recipient_getChatColorsTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/recipients/Recipient_getChatColorsTest.kt @@ -1,25 +1,34 @@ package org.thoughtcrime.securesms.recipients +import android.app.Application import android.graphics.Color +import androidx.test.core.app.ApplicationProvider import io.mockk.every import io.mockk.mockk import io.mockk.mockkObject +import io.mockk.mockkStatic import io.mockk.unmockkAll import org.junit.After import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config import org.thoughtcrime.securesms.conversation.colors.ChatColors import org.thoughtcrime.securesms.conversation.colors.ChatColorsPalette +import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider import org.thoughtcrime.securesms.database.RecipientDatabaseTestUtils.createRecipient +import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.keyvalue.ChatColorsValues import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.keyvalue.WallpaperValues import org.thoughtcrime.securesms.wallpaper.ChatWallpaper @Suppress("ClassName") -class Recipient_getChatColorsTest : BaseRecipientTest() { - +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE, application = Application::class) +class Recipient_getChatColorsTest { private val defaultChatColors = ChatColorsPalette.Bubbles.default.withId(ChatColors.Id.Auto) private val globalWallpaperChatColor = ChatColors.forColor(ChatColors.Id.BuiltIn, Color.RED) private val globalChatColor = ChatColors.forColor(ChatColors.Id.BuiltIn, Color.GREEN) @@ -29,6 +38,12 @@ class Recipient_getChatColorsTest : BaseRecipientTest() { @Before fun setUp() { + mockkStatic(AppDependencies::class) + every { AppDependencies.application } returns ApplicationProvider.getApplicationContext() + + mockkStatic(AttachmentSecretProvider::class) + every { AttachmentSecretProvider.getInstance(any()) } throws RuntimeException("Whoa, nelly!") + wallpaperValues = mockk() chatColorsValues = mockk() @@ -225,7 +240,7 @@ class Recipient_getChatColorsTest : BaseRecipientTest() { private fun createWallpaper( chatColors: ChatColors ): ChatWallpaper { - return mockk().apply { + return mockk { every { autoChatColors } answers { chatColors } } }