NoBeanDefFoundException с Mock ViewModel, тестирование с использованием Koin, Espresso - PullRequest
0 голосов
/ 06 ноября 2019

Я пытался получить простой Espresso тестовый модуль с Koin в качестве инструмента DI. Вот зависимости, которые я использую в build.gradle

    // testing with Koin
    // because of this
    // https://github.com/InsertKoinIO/koin/pull/604/commits/69391bc378bbb9007b9d82c46537e7d753be7ea3
    androidTestImplementation 'org.mockito:mockito-android:3.1.0'
    androidTestImplementation ("org.koin:koin-test:$koin_version") {
        exclude group: 'org.mockito'
    }

    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    // stuff like ActivityTestRule
    androidTestImplementation 'androidx.test:rules:1.2.0'
    // AndroidJUnit4
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    // test runner
    androidTestImplementation 'androidx.test:runner:1.2.0'

моем ViewModel объявлении

open class LoginViewModel(private val apiService: MockApiService) : ViewModel() {
..
..
}

, как его вводится в Activity

private val loginViewModel: LoginViewModel by viewModel()

Мой пользовательский TestRunner, чтобы создать пользовательский класс TestApplication

class MyTestRunner : AndroidJUnitRunner() {
    override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application {
        return super.newApplication(cl, TestApplication::class.java.name, context)
    }
}

TestApplication. Я проверил, что этот тестовый класс инициализируется при запуске теста

class TestApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        startKoin {
            androidLogger()
            androidContext(this@TestApplication)
            modules(emptyList())
        }
    }
}

Вот мой фактический androidTest. Это не происходит, как только действие начинается с NoBeanDefFoundException

Не найдено определение для com.abhishek.mvvmdemo.onboarding.LoginViewModel '.

@RunWith(AndroidJUnit4::class)
@LargeTest
class LoginActivityTest : KoinTest {
    private lateinit var loginViewModel: LoginViewModel

    @get:Rule
    val activityRule = ActivityTestRule(LoginActivity::class.java)

    @Before
    fun beforeTest() {
        loginViewModel = declareMock()
        loadKoinModules(
            module {
//                single { ApiModule.providesApiService() }
                viewModel { loginViewModel }
            }
        )
    }

    @Test
    fun testProgress() {
        activityRule.launchActivity(null)
        onView(withId(R.id.emailEt))
            .perform(ViewActions.typeText("abhishek"))
    }

    @After
    fun afterTest() {
        stopKoin()
    }
}

Я пробовал много перестановок и комбинаций, но мне не повезло. У меня также есть следующая конфигурация в моем gradle


testOptions {
        animationsDisabled = true
    }

    packagingOptions {
        pickFirst 'mockito-extensions/org.mockito.plugins.MockMaker'
    }

и

testInstrumentationRunner "com.abhishek.mvvmdemo.MyTestRunner"

TL; DR

Вот это образец github , который воспроизводит проблему

1 Ответ

1 голос
/ 06 ноября 2019

Здесь происходит то, что ActivityTestRule запускает действие до вашего @Before метода, поэтому у макета нет шансов на инициализацию.

Из официальной документации ,

Это правило обеспечивает функциональное тестирование одного действия. Если для launchActivity задано значение true в конструкторе, тестируемое действие будет запускаться перед каждым тестом, помеченным с помощью Test, и перед методами, помеченными с помощью Before, и оно будет прекращено после завершения теста и завершения методов, аннотированных с помощью After.

Вместо этого следует указать, что вы не хотите запускать действие автоматически, используя этот конструктор

ActivityTestRule (Class<T> activityClass, 
                boolean initialTouchMode, 
                boolean launchActivity)

Затем в своем методе тестирования вы можете запуститьактивность вручную

activityRule.launchActivity(null)

Кроме того, вы можете проверить https://mockk.io/ для насмешек. Вам не нужно будет объявлять ваши классы как open.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...