mirror of
https://github.com/bitwarden/android.git
synced 2025-12-10 08:35:05 -06:00
Add example test for MainViewModel (#113)
This commit is contained in:
parent
c8194545a4
commit
d1b5f3078e
13
.github/workflows/test.yml
vendored
13
.github/workflows/test.yml
vendored
@ -55,15 +55,26 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-
|
||||
|
||||
- name: Configure Ruby
|
||||
uses: ruby/setup-ruby@0cde4689ba33c09f1b890c1725572ad96751a3fc # v1.178.0
|
||||
with:
|
||||
bundler-cache: true
|
||||
|
||||
- name: Configure JDK
|
||||
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
|
||||
- name: Install Fastlane
|
||||
run: |
|
||||
gem install bundler:2.2.27
|
||||
bundle config path vendor/bundle
|
||||
bundle install --jobs 4 --retry 3
|
||||
|
||||
- name: Build and test
|
||||
run: |
|
||||
./gradlew testDebug lintDebug
|
||||
bundle exec fastlane check
|
||||
|
||||
- name: Upload to codecov.io
|
||||
uses: codecov/codecov-action@125fc84a9a348dbcf27191600683ec096ec9021c # v4.4.1
|
||||
|
||||
@ -141,6 +141,61 @@ dependencies {
|
||||
androidTestImplementation(libs.bundles.tests.instrumented)
|
||||
}
|
||||
|
||||
kover {
|
||||
currentProject {
|
||||
sources {
|
||||
excludeJava = true
|
||||
}
|
||||
}
|
||||
reports {
|
||||
filters {
|
||||
excludes {
|
||||
androidGeneratedClasses()
|
||||
annotatedBy(
|
||||
// Compose previews
|
||||
"androidx.compose.ui.tooling.preview.Preview",
|
||||
// Manually excluded classes/files/etc.
|
||||
"com.bitwarden.authenticator.data.platform.annotation.OmitFromCoverage",
|
||||
)
|
||||
classes(
|
||||
// Navigation helpers
|
||||
"*.*NavigationKt*",
|
||||
// Composable singletons
|
||||
"*.*ComposableSingletons*",
|
||||
// Generated classes related to interfaces with default values
|
||||
"*.*DefaultImpls*",
|
||||
// Databases
|
||||
"*.database.*Database*",
|
||||
"*.dao.*Dao*",
|
||||
// Dagger Hilt
|
||||
"dagger.hilt.*",
|
||||
"hilt_aggregated_deps.*",
|
||||
"*_Factory",
|
||||
"*_Factory\$*",
|
||||
"*_*Factory",
|
||||
"*_*Factory\$*",
|
||||
"*.Hilt_*",
|
||||
"*_HiltModules",
|
||||
"*_HiltModules\$*",
|
||||
"*_Impl",
|
||||
"*_Impl\$*",
|
||||
"*_MembersInjector",
|
||||
)
|
||||
packages(
|
||||
// Dependency injection
|
||||
"*.di",
|
||||
// Models
|
||||
"*.model",
|
||||
// Custom UI components
|
||||
"com.bitwarden.authenticator.ui.platform.components",
|
||||
// Theme-related code
|
||||
"com.bitwarden.authenticator.ui.platform.theme",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protobuf {
|
||||
protoc {
|
||||
artifact = libs.google.protobuf.protoc.get().toString()
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
package com.bitwarden.authenticator
|
||||
|
||||
import com.bitwarden.authenticator.data.platform.repository.SettingsRepository
|
||||
import com.bitwarden.authenticator.ui.platform.base.BaseViewModelTest
|
||||
import com.bitwarden.authenticator.ui.platform.feature.settings.appearance.model.AppTheme
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class MainViewModelTest : BaseViewModelTest() {
|
||||
|
||||
private val mutableAppThemeFlow = MutableStateFlow(AppTheme.DEFAULT)
|
||||
private val mutableScreenCaptureAllowedFlow = MutableStateFlow(false)
|
||||
private val settingsRepository = mockk<SettingsRepository> {
|
||||
every { appTheme } returns AppTheme.DEFAULT
|
||||
every { appThemeStateFlow } returns mutableAppThemeFlow
|
||||
every { isScreenCaptureAllowedStateFlow } returns mutableScreenCaptureAllowedFlow
|
||||
}
|
||||
private lateinit var mainViewModel: MainViewModel
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mainViewModel = MainViewModel(settingsRepository)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on AppThemeChanged should update state`() {
|
||||
assertEquals(
|
||||
MainState(
|
||||
theme = AppTheme.DEFAULT,
|
||||
),
|
||||
mainViewModel.stateFlow.value,
|
||||
)
|
||||
mainViewModel.trySendAction(
|
||||
MainAction.Internal.ThemeUpdate(
|
||||
theme = AppTheme.DARK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
MainState(
|
||||
theme = AppTheme.DARK,
|
||||
),
|
||||
mainViewModel.stateFlow.value,
|
||||
)
|
||||
|
||||
verify {
|
||||
settingsRepository.appTheme
|
||||
settingsRepository.appThemeStateFlow
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.bitwarden.authenticator.ui.platform.base
|
||||
|
||||
import app.cash.turbine.ReceiveTurbine
|
||||
import app.cash.turbine.TurbineContext
|
||||
import app.cash.turbine.turbineScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
|
||||
abstract class BaseViewModelTest {
|
||||
@Suppress("unused", "JUnitMalformedDeclaration")
|
||||
@RegisterExtension
|
||||
protected open val mainDispatcherExtension = MainDispatcherExtension()
|
||||
|
||||
protected suspend fun <S : Any, E : Any, T : BaseViewModel<S, E, *>> T.stateEventFlow(
|
||||
backgroundScope: CoroutineScope,
|
||||
validate: suspend TurbineContext.(
|
||||
stateFlow: ReceiveTurbine<S>,
|
||||
eventFlow: ReceiveTurbine<E>,
|
||||
) -> Unit,
|
||||
) {
|
||||
turbineScope {
|
||||
this.validate(
|
||||
this@stateEventFlow.stateFlow.testIn(backgroundScope),
|
||||
this@stateEventFlow.eventFlow.testIn(backgroundScope),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
package com.bitwarden.authenticator.ui.platform.base
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestDispatcher
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.setMain
|
||||
import org.junit.jupiter.api.extension.AfterAllCallback
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.junit.jupiter.api.extension.ExtensionContext
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
|
||||
/**
|
||||
* JUnit 5 Extension for automatically setting a [testDispatcher] as the "main" dispatcher.
|
||||
*
|
||||
* Note that this may be used as a normal class property with [RegisterExtension] or may be applied
|
||||
* directly to a test class using [ExtendWith].
|
||||
*/
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class MainDispatcherExtension(
|
||||
private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(),
|
||||
) : AfterAllCallback,
|
||||
AfterEachCallback,
|
||||
BeforeAllCallback,
|
||||
BeforeEachCallback {
|
||||
override fun afterAll(context: ExtensionContext?) {
|
||||
Dispatchers.resetMain()
|
||||
}
|
||||
|
||||
override fun afterEach(context: ExtensionContext?) {
|
||||
Dispatchers.resetMain()
|
||||
}
|
||||
|
||||
override fun beforeAll(context: ExtensionContext?) {
|
||||
Dispatchers.setMain(testDispatcher)
|
||||
}
|
||||
|
||||
override fun beforeEach(context: ExtensionContext?) {
|
||||
Dispatchers.setMain(testDispatcher)
|
||||
}
|
||||
}
|
||||
@ -19,7 +19,7 @@ platform :android do
|
||||
|
||||
desc "Runs tests"
|
||||
lane :check do
|
||||
gradle(task: "check")
|
||||
gradle(tasks: ["check","koverXmlReportDebug"])
|
||||
end
|
||||
|
||||
desc "Apply build version information"
|
||||
|
||||
@ -47,7 +47,7 @@ kotlinCompilerExtensionVersion = "1.5.14"
|
||||
kotlinxCollectionsImmutable = "0.3.7"
|
||||
kotlinxCoroutines = "1.8.1"
|
||||
kotlinxSerialization = "1.6.3"
|
||||
kotlinxKover = "0.7.6"
|
||||
kotlinxKover = "0.8.0"
|
||||
ksp = "1.9.24-1.0.20"
|
||||
mockk = "1.13.10"
|
||||
okhttp = "4.12.0"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user