Как переопределить внедренный Бин внутри ViewModel в UnitTests с заглушкой на Koin Android - PullRequest
2 голосов
/ 07 ноября 2019

Я пишу UnitTests для ViewModel / StateMachine (используя шаблон MVI). ViewModel имеет встроенный API-компонент (встроенный с Retrofit)

class UserViewModel(
    private val API: API
)

object UserModule {
    fun get(): Module {
        return module {
            viewModel { UserViewModel(api = get()) }
        }
    }
}

object NetworkModule {
    fun get(): Module {
        return module {
            ... // various retrofit Beans
            single{ Api(retrofit = get()) }
        }
    }
}

Это работает в моем приложении, но когда UnitTesting я должен был заглушить ответы от API, в одном тесте заглушить его с ошибкой, вдругая заглушка с ложным ответом, так что наличие некоторого MockNetworkModule, MockFailingNetworkModule с тем же интерфейсом кажется излишним, и это не так быстро, как подготовка фиктивных данных в блоке тестового кода.

Вот как япопытайтесь заглушить вызовы, но он все еще использует старую реализацию и выполняет сетевые вызовы

class UserTest : KoinTest {
    @get:Rule
    val schedulers = RxImmediateSchedulerRule()

    private val viewModel: UserViewModel by inject()

    @Before
    fun before() {
        startKoin {
            modules(
                listOf(
                    UserModule.get(),
                    NetworkModule.get()
                )
            )
        }
    }

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

Мои тесты написаны так (аналогично тому, что я прочитал из документации Koin):

@Test
fun `user test passing`() {
    val mockUserData = UserData("name", "surname")

    declareMock<Api> {
        given(this.getUserData()).willReturn { Single.just(mockUserData) }
    }

    viewModel.refresh() // calls api.getUserData() inside

    ... expecting mockUserData but getting real api call
}

@Test
fun `user test failing`() {
    declareMock<Api> {
        given(this.getUserData()).willReturn { Single.error(Exception("mock")) }
    }

    viewModel.refresh() // calls api.getUserData() inside

    ... expecting exception but getting real api call
}

Я также пытался declareMock<UserViewModel>{ given(this.api.getUserData()} ..., но имел NullPointerException на this.api.

TL; DR Как правильно заглушить уже внедренный компонент внутри viewModel для UnitTestingна лету

...