Убираем все на всякий случай

#android

Вопрос:

Убираем все на всякий случай.

Комментарии:

1. Вы следили за этой настройкой тестирования рукояти? youtube.com/watch?v=nOp_CEP_EjM

2. Эта настройка предназначена для тестирования контрольно-измерительных приборов, мой модульный тест @muetzenflo

3. В таком случае ответ прост: это не сработает. У UnitTests нет AndroidContext. Они возможны только для чистого кода Kotlin (логика, отличная от Android). Как только вам понадобится что-то вроде Context или Application (что является частью Hilt), вам нужно будет использовать инструментальные тесты. Отказ от ответственности: Я не профессионал в тестировании, и есть вероятность, что прямо сейчас я несу чушь. Но я совершенно уверен, что рукоять не может использоваться в чистых юниттестах.

4. Спасибо вам за ваш ответ. Да, я так и подумал, вопрос в том, могу ли я запускать тесты инструментов, такие как модульные тесты? У меня также нет опыта в тестировании, но если бы я каким-то образом мог получить контекст приложения и перейти к hilt, это было бы потрясающе. Для этого потребуется настроить его так, как я еще не пробовал, но буду с нетерпением ждать, чтобы сделать это, если это возможно.

5. Хорошо, я проверю менее чем через 2 дня, если это сработает, я скажу вам, чтобы вы опубликовали правильный ответ. Спасибо!

Ответ №1:

Вы сталкиваетесь с двумя различными проблемами:

  1. Использование рукояти в едином тесте
  2. Нужно ввести текст приложения в UnitTest

объявление 1) Я на 90% уверен, что вы не можете использовать Hilt в UnitTests, но я с радостью обновлю этот ответ, если кто-нибудь предоставит другую информацию. Почему нельзя использовать Эфес в бронежилетах? По той же причине, что и номер 2 (см. Ниже), поскольку рукоять плотно связана с конструкцией андроида.

объявление 2) Это определенно невозможно, и на самом деле основное различие между UnitTests и инструментальными тестами на Android: последние выполняются в среде Android (реальное устройство, эмулятор и т. Д.). Из-за этого можно тестировать компоненты вашего кода, использующие классы Android. Наиболее знаменито ApplicationContext , Context , Activity и Fragment . ЮнитТесты, с другой стороны, являются необработанными логическими тестами и не связаны с какими-либо компонентами платформы Android. Для UnitTest не требуется класс Android. Ни один класс Android не доступен для UnitTests.

Таким образом, в вашем случае вы хотите использовать Hilt для теста, в который необходимо ввести текст приложения. Оба являются сильными индикаторами того, что вы должны сделать это в тесте инструментов. Вот пошаговая инструкция по настройке рукоятки для тестирования контрольно-измерительных приборов, как описано в этом видео:

https://www.youtube.com/watch?v=nOp_CEP_EjM

  1. добавьте следующие зависимости сортировки:
 androidTestImplementation "com.google.dagger:hilt-android-testing:2.38.1" 
kaptAndroidTest "com.google.dagger:hilt-android-comiler:2.38.1"
 
  1. Чтобы использовать эфес, вам нужно поменять AndroidJUnitRunner его на небольшой пользовательский раннер. Для этого создайте это HiltTestRunner :
 import android.app.Application
import android.content.Context
import androidx.test.runner.AndroidJUnitRunner
import dagger.hilt.android.testing.HiltTestApplication

class HiltTestRunner : AndroidJUnitRunner() {

    override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application {
        return super.newApplication(cl, HiltTestApplication::class.java.name, context)
    }
}
 
  1. Чтобы рассказать gradle о новом тестовом бегуне, откройте свою /app/build.gradle и обменяйтесь этой строкой:

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

со ссылкой на класс HiltTestRunner , который вы только что создали:

testInstrumentationRunner "your.package.HiltTestRunner"

В принципе, так оно и есть. Теперь вы можете создать новый модуль в своих тестовых папках точно так же, как вы сделали бы это в обычной папке приложения. Например:

 @Module
@InstallIn(SingletonComponent::class)
class TestDatabaseModule {
    
    @Provides
    @Named("test_database")
    fun provideDatabase(@ApplicationContext applicationContext: Context): MyDatabase {
        return Room.inMemoryDatabaseBuilder(applicationContext, MyDatabase::class.java)
            .allowMainThreadQueries()
            .build()
    }
}
 

Чтобы внедрить эту базу данных в свой тестовый код, вам необходимо создать HiltAndroidRule и вызвать hiltRule.inject() @Before метод:

 @HiltAndroidTest
class UserDaoTest {

    @get:Rule
    var hiltRule = HiltAndroidRule(this)

    @get:Rule
    val testCoroutineRule = TestCoroutineRule()

    @Inject
    lateinit var database: MyDatabase

    private lateinit var sut: UserDao

    @Before
    fun createDb() {
        hiltRule.inject()
        sut = database.userDao()
    }

    @After
    @Throws(IOException::class)
    fun closeDb() {
        database.clearAllTables()
        database.close()
    }

    @Test
    @Throws(Exception::class)
    fun insertAndGetUserFromDb_success() = testCoroutineRule.runBlockingTest {

        // Given a database with 1 user
        val newUser = UserFakes.get()

        sut.insert(newUser)

        // When fetching the user
        sut.get().test {

            // Then the user fields should match 
            val user = awaitItem()
            assert(user.id == newUser.id)
            assert(user.name == newUser.name)
        }

    }
}
 

Дополнительная информация: Я использую турбину для упрощения потоков тестирования. Это часть кода выше, в которой я вызываю .test {} Поток и awaitItem() жду результата потока. Видишь турбину readme.md для получения дополнительной информации.