繁体   English   中英

Koin 测试 declareMock 不适用于倍数声明

[英]Koin test declareMock not working with multiples declaration

我试图声明两个模拟,但我得到一个 java.lang.ClassCastException。

我正在尝试测试我的 MainActivity(它有一个 MainViewModel),所以我需要模拟 MainViewModel。 问题是当我启动 MainActivity 进行测试时,SplashFragment 被注入,因为我正在使用导航组件并且我的 MainActivity 包含一个 NavHostFragment 并且默认情况下启动 SplashFragment(它有一个 SplashViewModel)。

总结:App -> MainActivity(尝试测试MainActivity中的一些常用组件) -> Splash Fragment

private val testViewState = MediatorLiveData<MainViewState>()
private val testSplashViewState = MediatorLiveData<SplashViewState>()

@Rule
@JvmField
var mockSplashViewModelRule = MockProviderRule.create {
    mock(SplashViewModel::class.java)
}

@Rule
@JvmField
var mockViewModelRule = MockProviderRule.create {
    mock(MainViewModel::class.java)
}


private fun launchMainActivity() {
    declareMock<SplashViewModel> {
        given(viewState).willReturn(testSplashViewState)
    }

    declareMock<MainViewModel> {
        given(viewState).willReturn(testViewState)
    }
    activityScenarioRule.scenario
}

我收到此错误: java.lang.ClassCastException:SplashViewModel 无法转换为 MainViewModel

如果我没有声明我得到的SplashViewModel:java.lang.RuntimeException:org.koin.core.error.NoBeanDefFoundException:没有找到 class 的定义:'SplashViewModel'。 检查你的定义!

有任何想法吗?

我是这样解决的:

private val testSplashViewState = MediatorLiveData<SplashViewState>()
private val testViewState = MediatorLiveData<MainViewState>()

@Mock
private lateinit var mainViewModel: MainViewModel

@Mock
private lateinit var splashViewModel: SplashViewModel

@Rule
@JvmField
var activityScenarioRule = LateInitActivityScenarioRule(MainActivity::class.java, false)

val module = module(createdAtStart = true, override = true) {
    viewModel { splashViewModel }
    viewModel { mainViewModel }
}

@Before
fun setupMainActivityTest() {
    loadKoinModules(module)
}

@After
fun afterMainActivityTest() {
    unloadKoinModules(module)
}

private fun launchMainActivity() {
    testSplashViewState.value = SplashViewState()
    whenever(splashViewModel.viewState).thenReturn(testSplashViewState)

    testViewState.value = MainViewState()
    whenever(mainViewModel.viewState).thenReturn(testViewState)
    activityScenarioRule.scenario
}





/**
 * Copyright 2018 The Android Open Source Project
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import android.app.Activity;
import android.content.Intent;

import androidx.annotation.Nullable;
import androidx.test.core.app.ActivityScenario;

import org.junit.rules.ExternalResource;

import static androidx.test.internal.util.Checks.checkNotNull;

/**
 * PrincipalActivityScenarioRule launches a given activity before the test starts and closes after the test.
 *
 * <p>You can access to scenario interface via {@link #getScenario()} method. You may finish your
 * activity manually in your test, it will not cause any problems and this rule does nothing after
 * the test in such cases.
 *
 * <p>This rule is an upgraded version of {@link androidx.test.rule.ActivityTestRule}. The previous
 * version will be deprecated and eventually be removed from the library in the future.
 *
 * <pre>{@code
 * Example:
 *  }{@literal @Rule}{@code
 *   PrincipalActivityScenarioRule<MyActivity> rule = new PrincipalActivityScenarioRule<>(MyActivity.class);
 *
 *  }{@literal @Test}{@code
 *   public void myTest() {
 *     ActivityScenario<MyActivity> scenario = rule.getScenario();
 *     // Your test code goes here.
 *   }
 * }</pre>
 */
public final class LateInitActivityScenarioRule<A extends Activity> extends ExternalResource {

    /**
     * Same as {@see java.util.function.Supplier} which requires API level 24.
     *
     * @hide
     */
    interface Supplier<T> {
        T get();
    }

    private Supplier<ActivityScenario<A>> scenarioSupplier;
    @Nullable
    private ActivityScenario<A> scenario;

    private boolean initOnBefore;

    /**
     * Constructs PrincipalActivityScenarioRule for a given activity class.
     *
     * @param activityClass an activity class to launch
     */
    public LateInitActivityScenarioRule(Class<A> activityClass, boolean initOnBefore) {
        this.initOnBefore = initOnBefore;
        scenarioSupplier = () -> ActivityScenario.launch(checkNotNull(activityClass));
    }

    /**
     * Constructs PrincipalActivityScenarioRule for a given activity class and intent.
     *
     * @param startActivityIntent an intent to start the activity
     */
    public LateInitActivityScenarioRule(Intent startActivityIntent, boolean initOnBefore) {
        this.initOnBefore = initOnBefore;
        scenarioSupplier = () -> ActivityScenario.launch(checkNotNull(startActivityIntent));
    }

    @Override
    protected void before() throws Throwable {
        if (initOnBefore) {
            ensureScenario();
        }
    }

    @Override
    protected void after() {
        if (scenario != null) {
            scenario.close();
        }
    }

    /**
     * Returns {@link ActivityScenario} of the given activity class.
     *
     * @return a non-null {@link ActivityScenario} instance
     * @throws {@see NullPointerException} if you call this method while test is not running
     */
    public ActivityScenario<A> getScenario() {
        ensureScenario();
        return checkNotNull(scenario);
    }

    /**
     * Returns {@link ActivityScenario} of the given activity class.
     *
     * @return a non-null {@link ActivityScenario} instance
     * @throws {@see NullPointerException} if you call this method while test is not running
     */
    public ActivityScenario<A> createScenario(Intent intent) {
        scenarioSupplier = () -> ActivityScenario.launch(checkNotNull(intent));
        ensureScenario();
        return checkNotNull(scenario);
    }

    private void ensureScenario() {
        if (scenario == null) {
            scenario = scenarioSupplier.get();
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM