---
# System prepended metadata

title: Unit Test - 使用hilt測試5 - 改寫Dao Testing
tags: [Unit Test, hilt, test, kotlin]

---

# Unit Test - 使用hilt測試5 - 改寫Dao Testing


---


## 開始吧

### 情境
在[這一篇](https://hackmd.io/QPN8oKVWTj6EkD2y0h7UuQ?view)
我們用一般的方法，在每次測試前產生database instanse，這次要改成使用DI

### 新增dependencies
```kotlin=
//hilt_version = 2.37
    //hilt for test
    androidTestImplementation "com.google.dagger:hilt-android-testing:$hilt_version"

    kaptAndroidTest "com.google.dagger:hilt-compiler:$hilt_version"
```

### 定義HiltTestRunner
* 因為Database會用到application
* 使用hilt測試application需要自定義Test runner
* 在androidTest目錄下新建類別如下
```kotlin=

class HiltTestRunner: AndroidJUnitRunner() {

    override fun newApplication(
        cl: ClassLoader?,
        className: String?,
        context: Context?
    ): Application {
    //第二個參數className改成下面HiltTestApplication::class.java.name
        return super.newApplication(cl, HiltTestApplication::class.java.name, context)
    }
}
```
### 把test Runner指定到剛剛建立的HiltTestRunner
```kotlin=
// Gradle Module
defaultConfig {
        applicationId "com.androiddevs.shoppinglisttestingyt"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

**替換掉**
//        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        testInstrumentationRunner "com.androiddevs.shoppinglisttestingyyt.HiltTestRunner"
    }
```

### 移除舊有的JUnit Runner
* 移除RunWith，因為我們已經指定到hiltTestRunner
```kotlin=

    @ExperimentalCoroutinesApi
    @RunWith(AndroidJUnit4::class)  //這一行移除
    @SmallTest
    class ShoppingDaoTest {
    
    }
```

### 新增Module來提供database
* 新增package di
* 新增物件TestAppModule
* 這邊使用@Named()是要讓hilt知道要使用哪個Module提供instance，正常來說我們會有一個app使用的Module也會提供database instance，所以使用@Named指定
```kotlin=

@Module
@InstallIn(SingletonComponent::class)
object TestAppModule {

    @Provides
    @Named("test_db")
    fun provideInMemoryDb(@ApplicationContext context: Context) =
        Room.inMemoryDatabaseBuilder(context, ShoppingItemDatabase::class.java)
            .allowMainThreadQueries()
            .build()
}
```

### Dao refactor
* 加入聲明@HiltAndroidTest
* 新增Rule
```kotlin=
@ExperimentalCoroutinesApi
@SmallTest
@HiltAndroidTest
class ShoppingDaoTest {

    //for hilt rule
    @get:Rule
    var hiltRule = HiltAndroidRule(this)

    @get:Rule
    var instantTaskExecutorRule = InstantTaskExecutorRule()

    //注入Database，著名是test_db，這樣它才知道要去TestAppModule拿instance
    @Inject
    @Named("test_db")
    lateinit var database: ShoppingItemDatabase

    private lateinit var dao: ShoppingDao

    @Before
    fun setUp() {
        //初始化提供注入 取代原本在這裡初始化database
        hiltRule.inject()
        dao = database.shoppingDao()
    }
    
}
```

### 跑測試吧...
* ~~很遺憾.....跑不出來.......~~
* ~~根據官方說法[Android studio run test not working](https://dagger.dev/hilt/gradle-setup.html#running-with-android-studio)~~
* ~~除了dependency版本要match以外，看來test還有些許限制跟bug未解~~
* ~~[等解bug吧](https://issuetracker.google.com/issues/37076369?pli=1)~~
![](https://i.imgur.com/79ztoMv.png)


## 期待hilt更完善吧~~~~:joy_cat::joy_cat::joy_cat::joy_cat::joy_cat:

### 發現手誤
* 多打了一個y
```kotlin=

 //之前打錯的路徑
 testInstrumentationRunner "com.androiddevs.shoppinglisttestingyyt.HiltTestRunner"
 
 //修正後的路徑
  testInstrumentationRunner "com.androiddevs.shoppinglisttestingyt.HiltTestRunner"
  
```
![](https://i.imgur.com/yLmHHUg.png)




###### tags: `test` `Unit Test` `hilt` `kotlin`