首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >安卓RxJava 2 JUnit测试- getMainLooper in android.os.Looper not mocked RuntimeException

安卓RxJava 2 JUnit测试- getMainLooper in android.os.Looper not mocked RuntimeException
EN

Stack Overflow用户
提问于 2017-04-12 05:14:48
回答 9查看 34.3K关注 0票数 68

尝试为使用observeOn(AndroidSchedulers.mainThread())的演示者运行JUnit测试时遇到RuntimeException。

由于它们是纯JUnit测试,而不是Android工具测试,它们不能访问Android依赖项,导致我在执行测试时遇到以下错误:

代码语言:javascript
运行
复制
java.lang.ExceptionInInitializerError
    at io.reactivex.android.schedulers.AndroidSchedulers$1.call(AndroidSchedulers.java:35)
    at io.reactivex.android.schedulers.AndroidSchedulers$1.call(AndroidSchedulers.java:33)
    at io.reactivex.android.plugins.RxAndroidPlugins.callRequireNonNull(RxAndroidPlugins.java:70)
    at io.reactivex.android.plugins.RxAndroidPlugins.initMainThreadScheduler(RxAndroidPlugins.java:40)
    at io.reactivex.android.schedulers.AndroidSchedulers.<clinit>(AndroidSchedulers.java:32)
    …
Caused by: java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.
    at android.os.Looper.getMainLooper(Looper.java)
    at io.reactivex.android.schedulers.AndroidSchedulers$MainHolder.<clinit>(AndroidSchedulers.java:29)
    ...


java.lang.NoClassDefFoundError: Could not initialize class io.reactivex.android.schedulers.AndroidSchedulers
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    …
EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2017-04-12 05:14:48

出现此错误的原因是,AndroidSchedulers.mainThread()返回的默认调度程序是LooperScheduler的一个实例,并且依赖于JUnit测试中不可用的Android依赖项。

我们可以通过在运行测试之前使用不同的调度程序初始化RxAndroidPlugins来避免此问题。您可以在@BeforeClass方法中执行此操作,如下所示:

代码语言:javascript
运行
复制
@BeforeClass
public static void setUpRxSchedulers() {
    Scheduler immediate = new Scheduler() {
        @Override
        public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
            // this prevents StackOverflowErrors when scheduling with a delay
            return super.scheduleDirect(run, 0, unit);
        }

        @Override
        public Worker createWorker() {
            return new ExecutorScheduler.ExecutorWorker(Runnable::run);
        }
    };

    RxJavaPlugins.setInitIoSchedulerHandler(scheduler -> immediate);
    RxJavaPlugins.setInitComputationSchedulerHandler(scheduler -> immediate);
    RxJavaPlugins.setInitNewThreadSchedulerHandler(scheduler -> immediate);
    RxJavaPlugins.setInitSingleSchedulerHandler(scheduler -> immediate);
    RxAndroidPlugins.setInitMainThreadSchedulerHandler(scheduler -> immediate);
}

或者,您可以创建一个自定义TestRule,它将允许您在多个测试类中重用初始化逻辑。

代码语言:javascript
运行
复制
public class RxImmediateSchedulerRule implements TestRule {
    private Scheduler immediate = new Scheduler() {
        @Override
        public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
            // this prevents StackOverflowErrors when scheduling with a delay
            return super.scheduleDirect(run, 0, unit);
        }

        @Override
        public Worker createWorker() {
            return new ExecutorScheduler.ExecutorWorker(Runnable::run);
        }
    };

    @Override
    public Statement apply(final Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                RxJavaPlugins.setInitIoSchedulerHandler(scheduler -> immediate);
                RxJavaPlugins.setInitComputationSchedulerHandler(scheduler -> immediate);
                RxJavaPlugins.setInitNewThreadSchedulerHandler(scheduler -> immediate);
                RxJavaPlugins.setInitSingleSchedulerHandler(scheduler -> immediate);
                RxAndroidPlugins.setInitMainThreadSchedulerHandler(scheduler -> immediate);

                try {
                    base.evaluate();
                } finally {
                    RxJavaPlugins.reset();
                    RxAndroidPlugins.reset();
                }
            }
        };
    }
}

然后可以将其应用于测试类。

代码语言:javascript
运行
复制
public class TestClass {
    @ClassRule public static final RxImmediateSchedulerRule schedulers = new RxImmediateSchedulerRule();

    @Test
    public void testStuff_stuffHappens() {
       ...
    }
}

这两种方法都将确保在执行任何测试和访问AndroidSchedulers之前覆盖默认调度程序。

使用用于单元测试的即时调度器覆盖RxJava调度器还将确保被测试代码中的RxJava使用同步运行,这将使编写单元测试变得更加容易。

资料来源:

https://www.infoq.com/articles/Testing-RxJava2 https://medium.com/@peter.tackage/overriding-rxandroid-schedulers-in-rxjava-2-5561b3d14212

票数 83
EN

Stack Overflow用户

发布于 2017-10-12 14:27:11

我刚添加了

代码语言:javascript
运行
复制
RxAndroidPlugins.setInitMainThreadSchedulerHandler(scheduler -> Schedulers.trampoline());

@Before中的一个注解方法。

票数 50
EN

Stack Overflow用户

发布于 2018-07-18 05:08:26

我在测试LiveData时也遇到了同样的错误。在测试LiveData时,如果要测试的类同时具有后台线程和RxImmediateSchedulerRule,则除了RxImmediateSchedulerRule之外,还需要此InstantTaskExecutorRule

代码语言:javascript
运行
复制
@RunWith(MockitoJUnitRunner::class)
class MainViewModelTest {

    companion object {
        @ClassRule @JvmField
        val schedulers = RxImmediateSchedulerRule()
    }

    @Rule
    @JvmField
    val rule = InstantTaskExecutorRule()

    @Mock
    lateinit var dataRepository: DataRepository

    lateinit var model: MainViewModel

    @Before
    fun setUp() {
      model = MainViewModel(dataRepository)
    }

    @Test
    fun fetchData() {
      //given    
      val returnedItem = createDummyItem()    
      val observer = mock<Observer<List<Post>>>()    
      model.getPosts().observeForever(observer)    
      //when    
      liveData.value = listOf(returnedItem)    
      //than    
      verify(observer).onChanged(listOf(Post(returnedItem.id, returnedItem.title, returnedItem.url)))
    }

}

参考:https://pbochenski.pl/blog/07-12-2017-testing_livedata.html

票数 22
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43356314

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档