"// RemoteData: sealed type describing data loading state "// Initial/Loading/Success/Failure val apiData: RemoteData<String, Exception> = Initial "// …… )
val dataSource: SampleDataSource ) : ViewModel() { "// never allow others to mutate the state private val viewStatePublisher: MutableLiveData<SampleViewState> = MutableLiveData(SampleViewState()) val viewState: LiveData<SampleViewState> = viewStatePublisher fun loadData() { "// …… implement state changes "// …… start loading, subscribe result from data source, emit success or failure } }
Fragment() { private lateinit var viewModel: SampleViewModel override fun onCreate(savedInstanceState: Bundle?) { "// …… viewModel.loadData() viewModel.viewState.observe(this, Observer { state "-> when (it) { is Loading "-> "// show loading view is Success "-> "// apply data to UI is Failure "-> "// show error message } }) } }
SampleViewModelTest : Spek({ Feature("SampleViewModel#startLoading") { val dataSource: SampleDataSource by memoized(CachingMode.EACH_GROUP) { mockk<SampleDataSource>(relaxed = true) } Scenario("Load data successfully") { "// Test cases verifying state changes in successful scenario } Scenario("Load data unsuccessfully") { "// Test cases verifying state changes in failure scenario } } })
SampleViewModelTest : Spek({ Scenario("Load data successfully") { lateinit var viewModel: SampleViewModel lateinit var observer: Observer<SampleViewState> lateinit var changedStateSlot: CapturingSlot<SampleViewState> Given("ViewModel with initial state and state observer") { changedStateSlot = slot() observer = mockk(relaxed = true) { every { onChanged(capture(changedStateSlot)) } just Runs } every { dataSource.loadApiData() } returns Observable.just("foo") viewModel = NotificationViewModel(dataSource) } } })
of container this execution is on. val containerIndex = System.getenv("CIRCLE_NODE_INDEX")"?.toInt() "?: 0 "// Total number of containers running in parallel. val totalContainer = System.getenv("CIRCLE_NODE_TOTAL")"?.toInt() "?: 0 "// Select modules to run unit tests on the container val modules = project.subprojects .withIndex() .filter { it.index % totalContainer "== containerIndex } .map { it.value } "// Execute tests modules.forEach { module "-> "./gradlew :${module.name}:test".runCommand() } DroidKaigi 2020
"// buildSrc/src/main/kotlin/com/example/MyCustomTask.kt open class MyCustomTask : DefaultTask() { @Input lateinit var parameter: String @TaskAction fun doAction() { "// … do your job! } } DroidKaigi 2020
"// buildSrc/src/main/kotlin/com/example/MyCustomTask.kt open class MyCustomTask : DefaultTask() { @Input lateinit var parameter: String @TaskAction fun doAction() { "// … do your job! } } DroidKaigi 2020
"// buildSrc/src/main/kotlin/com/example/MyCustomTask.kt open class MyCustomTask : DefaultTask() { @Input lateinit var parameter: String @TaskAction fun doAction() { "// … do your job! } } DroidKaigi 2020
"// buildSrc/src/main/kotlin/com/example/MyCustomTask.kt open class MyCustomTask : DefaultTask() { @Input lateinit var parameter: String @TaskAction fun doAction() { "// … do your job! } } DroidKaigi 2020
Module A /module_a/ @KeithYokoma # Anyone in team_a can review changes in Module B /module_b/ @team_a # Either KeithYokoma or someone in team_a can review /module_c/ @KeithYokoma @team_a DroidKaigi 2020
Describe the change set in short ——> "## Kind <!—— Describe what kind of change? e.g. Bugfix, New feature, Design adjustment, etc…… ——> "## Details <!—— e.g. What caused the issue? How you solved it? Any caveats? Anything out of scope? ——> "## Links <!—— Put links related to this PR if any ——> - Task Ticket: - Design Doc: - Crashlytics Issue: "## Screenshot <!—— Put screenshots indicating what has been changed with this PR if any ——> Before | After :——:|:——: <img src="" width="300" "/>|<img src="" width="300" "/> DroidKaigi 2020
the last thing you should do" by Martin Fowler ▸ ϑϥάΛͭ͜ͱͷίετগͳ͔Βͣ͋Δ ▸ ༗ޮԽ͢ΔλΠϛϯά ▸ Θͳ͘ͳͬͨΒআ͢Δ ▸ ϑϥάΛ࣋ͭ΄͔ʹऔΓ͏Δબࢶ ▸ UI ͷͭͳ͗͜ΈΛ࠷ޙʹ͢Δ ▸ ػೳͦͷͷΛࡉ͔͘Θ͚ɺখ͘͞ϦϦʔε͢Δ DroidKaigi 2020 107