# Unit Test - 使用hilt測試9 - Testing Add Item --- ## 開始吧 ### 情境 ### 修改AddShoppingItemFragmen * 注入glide * 觀察者模式-當url變化.用glide讀取,insert data 做對應的動作 ```kotlin= class AddShoppingItemFragment @Inject constructor( val glide: RequestManager //注入glide ) : Fragment(R.layout.fragment_add_shopping_item) { lateinit var viewModel: ShoppingViewModel override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel = ViewModelProvider(requireActivity()).get(ShoppingViewModel::class.java) subscribeToObserver() btnAddShoppingItem.setOnClickListener { viewModel.insertShoppingItem( etShoppingItemName.text.toString(), etShoppingItemAmount.text.toString(), etShoppingItemPrice.text.toString() ) } ivShoppingImage.setOnClickListener { findNavController().navigate( AddShoppingItemFragmentDirections.actionAddShoppingItemFragmentToImagePickFragment() ) } val callback = object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { viewModel.setCurImageUrl("") findNavController().popBackStack() } } requireActivity().onBackPressedDispatcher.addCallback(callback) } private fun subscribeToObserver() { viewModel.curImageUrl.observe(viewLifecycleOwner, Observer { glide.load(it).into(ivShoppingImage) }) viewModel.insertShoppingItemStatus.observe(viewLifecycleOwner, Observer { it.getContentIfNotHandled()?.let { result -> when (result.status) { Status.SUCCESS -> { Snackbar.make( requireActivity().rootLayout, "Add Shopping Item", Snackbar.LENGTH_LONG ).show() findNavController().popBackStack() } Status.ERROR -> { Snackbar.make( requireActivity().rootLayout, result.message ?: "an unknown error occurred", Snackbar.LENGTH_LONG ).show() } Status.LOADING -> { /* NO-OP */ } } } }) } } ``` ### 修正ShoppingFragmentFactory * 增加glide的參數 ```kotlin= class ShoppingFragmentFactory @Inject constructor( private val imageAdapter: ImageAdapter, private val glide: RequestManager //注入用的 ) : FragmentFactory() { override fun instantiate(classLoader: ClassLoader, className: String): Fragment { return when (className) { ImagePickFragment::class.java.name -> ImagePickFragment(imageAdapter) //當實例化的fragment是底下這個,要傳遞glide做實例化 AddShoppingItemFragmen::class.java.name -> AddShoppingItemFragmen(glide) else -> super.instantiate(classLoader, className) } } } ``` ### 寫測試吧 * 打開之前的AddShoppingItemFragmentTest * 寫入一筆資料,並查詢DB是否有該筆資料 ```kotlin= @ExperimentalCoroutinesApi @MediumTest @HiltAndroidTest class AddShoppingItemFragmentTest { @get:Rule var hiltRule = HiltAndroidRule(this) @get:Rule var instantTaskExecutorRule = InstantTaskExecutorRule() @Before fun setup() { hiltRule.inject() } //新增factory @Inject lateinit var fragmentFactory: ShoppingFragmentFactory //新增測試 @Test fun clickInsertIntoDb_shoppingItemInsertedIntoDb() { val testViewModel = ShoppingViewModel(FakeRepository()) launchFragmentInHiltContainer<AddShoppingItemFragment>( fragmentFactory = fragmentFactory ) { viewModel = testViewModel } onView(withId(R.id.etShoppingItemName)).perform(replaceText("shopping item")) onView(withId(R.id.etShoppingItemAmount)).perform(replaceText("5")) onView(withId(R.id.etShoppingItemPrice)).perform(replaceText("5.5")) onView(withId(R.id.btnAddShoppingItem)).perform(click()) assertThat(testViewModel.shoppingItems.getOrAwaitValue()) .contains(ShoppingItem("shopping item", 5, 5.5f, "")) } @Test fun pressBackButton_popBackStack() { val navController = mock(NavController::class.java) launchFragmentInHiltContainer<AddShoppingItemFragment> { Navigation.setViewNavController(requireView(), navController) } pressBack() verify(navController).popBackStack() } @Test fun clickivShoppingImage_navigeteToImagePickFragment() { val navController = mock(NavController::class.java) launchFragmentInHiltContainer<AddShoppingItemFragment> { Navigation.setViewNavController(requireView(), navController) } onView(withId(R.id.ivShoppingImage)).perform(click()) verify(navController).navigate( AddShoppingItemFragmentDirections.actionAddShoppingItemFragmentToImagePickFragment() ) } @Test fun imageUrlIsEmpty_afterPooBackStack() { val testviewModel = ShoppingViewModel(FakeRepository()) val navController = mock(NavController::class.java) launchFragmentInHiltContainer<AddShoppingItemFragment> { Navigation.setViewNavController(requireView(), navController) viewModel = testviewModel } pressBack() val value = testviewModel.curImageUrl.getOrAwaitValue() assertThat(value).isEmpty() } } ``` ![](https://i.imgur.com/dITuj63.png) 參考資料 [ Philipp Lackner's channel](https://www.youtube.com/watch?v=6ZQ9v0KFiPA) ###### tags: `test` `Unit Test` `kotlin` `hilt`