iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 9
1
Mobile Development

Android × CI/CD 如何用基本的MVVM專案實現 CI/CD 系列 第 9

Day9 MVVM專案-1a

本篇會延續 Day7 MVVM專案-1 接著修改

今天會將result改為MediatorLiveData

MediatorLiveData簡而言之就是能同時觀察數個livedata
以result為例 原本是按plus後對left與right的數值相加
改成MediatorLiveData以後
left 或right數據變更時會即時通知result

調整result
先將val result = MutableLiveData("")
改為以下內容

Stage01ViewModel.kt

val result = MediatorLiveData<String>().apply {
   value = ""
   val plus: (String?) -> Unit = plus@{
       val leftNum = left.value?.toIntOrNull()
       if (leftNum == null) {
           visibleResult.value = false
           return@plus
       }
       val rightNum = right.value?.toIntOrNull()
       if (rightNum == null) {
           visibleResult.value = false
           return@plus
       }
       value = (leftNum + rightNum).toString()
       visibleResult.value = true
   }
   addSource(left, plus)
   addSource(right, plus)
}

addSource(觀察數據, 行為)
val plus這段的意思是當數據變更時 檢查left 或right 數值
如果其中一個非int或是為null 則改result的可見度為隱藏 並且return
否則相加 並且result的可見度為可見

這段code其實是把以下這兩段code給整合了

Stage01ViewModel.kt

fun plus() {
   val leftNum =
       left.value.toString().toIntOrNull() ?: run { visibleResult.value = false; return }
   val rightNum =
       right.value.toString().toIntOrNull() ?: run { visibleResult.value = false; return }
   result.value = (leftNum + rightNum).toString()
   visibleResult.value = true
}

Stage01Activity.kt

override fun onCreate(savedInstanceState: Bundle?) {
val setInvisibleResult = Observer<String?> { viewModel.visibleResult.value = false }
viewModel.left.observe(this, setInvisibleResult)
viewModel.right.observe(this, setInvisibleResult)
}

因為數據會即時判斷了
所以首頁針對left right的observe也可以移除了

在補上今天的測試案例
Stage01ViewModelTest.kt

@Test
fun one_plus_one_is_two() {
   // given
   val givenVal = "1"

   // when
   Espresso.onView(ViewMatchers.withId(R.id.et_left)).perform(ViewActions.typeText(givenVal))
   Espresso.onView(ViewMatchers.withId(R.id.et_right)).perform(ViewActions.typeText(givenVal))

   // then
   val expectedText = String.format(rule.activity.getString(R.string.stage01_result_format),givenVal, givenVal, "2")
   Espresso.onView(ViewMatchers.withId(R.id.tv_result)).check(
       ViewAssertions.matches(
           ViewMatchers.withText(expectedText)
       )
   )
}

然後運行時會發現之前寫的測試失敗了

原因是因為首頁的observe被拿掉了

現在數據變更時result的結果會根據fun plus() 即時顯示
而不是輸入數據時不管結果如何都先隱藏
所以result_should_be_invisible_when_input()也要做對應的調整

附上修正後的測試案例

@Before
fun reset() {
   Espresso.onView(ViewMatchers.withId(R.id.et_left)).perform(ViewActions.replaceText(""))
   Espresso.onView(ViewMatchers.withId(R.id.et_right)).perform(ViewActions.replaceText(""))
}

@Test
fun result_should_be_invisible_when_input() {
   // given
   plus() // result view is visible
   Espresso.onView(ViewMatchers.withId(R.id.tv_result)).check(ViewAssertionsEx.isVisibility())

   // when
   Espresso.onView(ViewMatchers.withId(R.id.et_left)).perform(ViewActions.replaceText(""))

   // then
   Espresso.onView(ViewMatchers.withId(R.id.tv_result)).check(ViewAssertionsEx.isInvisible())
}

最後附上今天的solution

https://github.com/mars1120/jetpackMvvmDemo/tree/mvvm-stage01a


上一篇
Day8 Espresso
下一篇
Day10 unit tests 介紹
系列文
Android × CI/CD 如何用基本的MVVM專案實現 CI/CD 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言