Rxjava2 유닛 테스트 출현: Android RxJava2 JUnit test - getMainLooper in android.os.Looper not mocked RuntimeException

7335 단어
최근 프로젝트에서 Rxjava를 Rxjava2로 업그레이드한 후 이전의 P, M(프로젝트는 MVP 구조를 바탕으로 하는) 층에 대해 단원 테스트를 진행할 때 다음과 같은 문제가 발생했다.
Android RxJava 2 JUnit test - getMainLooper in android.os.Looper not mocked RuntimeException
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.(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.(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)

이 문제가 발생한 이유는 AndroidSchedulers.mainThreadLooperScheduler의 실례로 되돌아왔지만 LooperScheduler는 안드로이드에 의존하여 순수한 자바의 단원 테스트에서 사용할 수 없기 때문이다.문제의 원인을 찾으면 해결하기가 훨씬 쉽다.단원 테스트가 실행되기 전에 안드로이드에 의존하지 않는 RxAndroidPlugins 을 초기화해야 합니다.다음은 두 가지 해결 방안을 제시한다.
시나리오 1:Scheduler에서 초기화@BeforeClass:
@BeforeClass
    public static void setUpRxSchedulers(){
        final Scheduler immediate = new Scheduler() {

            @Override
            public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
                return super.scheduleDirect(run, 0, unit);
            }

            @Override
            public Worker createWorker() {
                return new ExecutorScheduler.ExecutorWorker(new Executor() {
                    @Override
                    public void execute(@android.support.annotation.NonNull Runnable command) {
                        command.run();
                    }
                });
            }
        };

        RxJavaPlugins.setInitIoSchedulerHandler(new Function, Scheduler>() {
            @Override
            public Scheduler apply(@NonNull Callable schedulerCallable) throws Exception {
                return immediate;
            }
        });
        RxJavaPlugins.setInitComputationSchedulerHandler(new Function, Scheduler>() {
            @Override
            public Scheduler apply(@NonNull Callable schedulerCallable) throws Exception {
                return immediate;
            }
        });
        RxJavaPlugins.setInitNewThreadSchedulerHandler(new Function, Scheduler>() {
            @Override
            public Scheduler apply(@NonNull Callable schedulerCallable) throws Exception {
                return immediate;
            }
        });
        RxJavaPlugins.setInitSingleSchedulerHandler(new Function, Scheduler>() {
            @Override
            public Scheduler apply(@NonNull Callable schedulerCallable) throws Exception {
                return immediate;
            }
        });
        RxAndroidPlugins.setInitMainThreadSchedulerHandler(new Function, Scheduler>() {
            @Override
            public Scheduler apply(@NonNull Callable schedulerCallable) throws Exception {
                return immediate;
            }
        });
    }

이렇게 하면 문제를 해결할 수 있지만 모든 테스트 클래스에 이런 코드를 추가해야 합니다. 매우 번거롭습니다. 간단한 방법이 있습니까?물론 있습니다. 우리는 사용자 정의Scheduler를 할 수 있고 필요한 곳에서 직접 호출하면 됩니다.
시나리오 2:
사용자 정의TestRule를 통해 구현RxSchedulersOverrideRule:
public class RxSchedulersOverrideRule implements TestRule {


    private Scheduler immediate = new Scheduler() {

        @Override
        public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
            return super.scheduleDirect(run, 0, unit);
        }

        @Override
        public Worker createWorker() {
            return new ExecutorScheduler.ExecutorWorker(new Executor() {
                @Override
                public void execute(@android.support.annotation.NonNull Runnable command) {
                    command.run();
                }
            });
        }
    };

    @Override
    public Statement apply(final Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                RxJavaPlugins.setInitIoSchedulerHandler(new Function, Scheduler>() {
                    @Override
                    public Scheduler apply(@NonNull Callable schedulerCallable) throws Exception {
                        return immediate;
                    }
                });
                RxJavaPlugins.setInitComputationSchedulerHandler(new Function, Scheduler>() {
                    @Override
                    public Scheduler apply(@NonNull Callable schedulerCallable) throws Exception {
                        return immediate;
                    }
                });
                RxJavaPlugins.setInitNewThreadSchedulerHandler(new Function, Scheduler>() {
                    @Override
                    public Scheduler apply(@NonNull Callable schedulerCallable) throws Exception {
                        return immediate;
                    }
                });
                RxJavaPlugins.setInitSingleSchedulerHandler(new Function, Scheduler>() {
                    @Override
                    public Scheduler apply(@NonNull Callable schedulerCallable) throws Exception {
                        return immediate;
                    }
                });
                RxAndroidPlugins.setInitMainThreadSchedulerHandler(new Function, Scheduler>() {
                    @Override
                    public Scheduler apply(@NonNull Callable schedulerCallable) throws Exception {
                        return immediate;
                    }
                });

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

필요한 경우 다음과 같이 직접 호출하면 됩니다.
  @ClassRule
    public static RxSchedulersOverrideRule sSchedulersOverrideRule = new RxSchedulersOverrideRule();

좋은 웹페이지 즐겨찾기