我第一次面对单元测试,我想知道以下场景的最佳方法是什么。 我正在使用Mockito进行测试。以下测试用于逻辑(Presenter)层,我正在尝试验证视图的某些行为。
应用类
需要包含在测试中的Presenter方法:
public void loadWeather() {
CityDetailsModel selectedCity = getDbHelper().getSelectedCityModel();
if (selectedCity != null) {
getCompositeDisposableHelper().execute(
getApiHelper().weatherApiRequest(selectedCity.getLatitude(), selectedCity.getLongitude()),
new WeatherObserver(getMvpView()));
} else {
getMvpView().showEmptyView();
}
}
WeatherObserver :
public class WeatherObserver extends BaseViewSubscriber<DayMvpView, WeatherResponseModel> {
public WeatherObserver(DayMvpView view) {
super(view);
}
@Override public void onNext(WeatherResponseModel weatherResponseModel) {
super.onNext(weatherResponseModel);
if (weatherResponseModel.getData().isEmpty()) {
getMvpView().showEmptyView();
} else {
getMvpView().showWeather(weatherResponseModel.getData());
}
}
}
BaseViewSubscriber(每当我们想要默认错误处理时使用的默认DisposableObserver基类):
public class BaseViewSubscriber<V extends BaseMvpView, T> extends DisposableObserver<T> {
private ErrorHandlerHelper errorHandlerHelper;
private V view;
public BaseViewSubscriber(V view) {
this.view = view;
errorHandlerHelper = WeatherApplication.getApplicationComponent().errorHelper();
}
public V getView() {
return view;
}
public boolean shouldShowError() {
return true;
}
protected boolean shouldShowLoading() {
return true;
}
@Override public void onStart() {
if (!AppUtils.isNetworkAvailable(WeatherApplication.getApplicationComponent().context())) {
onError(new InternetConnectionException());
return;
}
if (shouldShowLoading()) {
view.showLoading();
}
super.onStart();
}
@Override public void onError(Throwable e) {
if (view == null) {
return;
}
if (shouldShowLoading()) {
view.hideLoading();
}
if (shouldShowError()) {
view.onError(errorHandlerHelper.getProperErrorMessage(e));
}
}
@Override public void onComplete() {
if (view == null) {
return;
}
if (shouldShowLoading()) {
view.hideLoading();
}
}
@Override public void onNext(T t) {
if (view == null) {
return;
}
}
}
CompositeDisposableHelper(CompositeDisposable helper class):
public class CompositeDisposableHelper {
public CompositeDisposable disposables;
public TestScheduler testScheduler;
@Inject public CompositeDisposableHelper(CompositeDisposable disposables) {
this.disposables = disposables;
testScheduler = new TestScheduler();
}
public <T> void execute(Observable<T> observable, DisposableObserver<T> observer) {
addDisposable(observable.subscribeOn(testScheduler)
.observeOn(testScheduler)
.subscribeWith(observer));
}
public void dispose() {
if (!disposables.isDisposed()) {
disposables.dispose();
}
}
public TestScheduler getTestScheduler() {
return testScheduler;
}
public void addDisposable(Disposable disposable) {
disposables.add(disposable);
}
}
我的测试:
@Test public void loadSuccessfully() {
WeatherResponseModel responseModel = new WeatherResponseModel();
List<WeatherModel> list = new ArrayList<>();
list.add(new WeatherModel());
responseModel.setData(list);
CityDetailsModel cityDetailsModel = new CityDetailsModel();
cityDetailsModel.setLongitude("");
cityDetailsModel.setLatitude("");
when(dbHelper.getSelectedCityModel()).thenReturn(cityDetailsModel);
when(apiHelper.weatherApiRequest(anyString(), anyString())).thenReturn(
Observable.just(responseModel));
dayPresenter.loadWeather();
compositeDisposableHelper.getTestScheduler().triggerActions();
verify(dayMvpView).showWeather(list);
verify(dayMvpView, never()).showEmptyView();
verify(dayMvpView, never()).onError(anyString());
}
当我尝试运行测试时,我得到NullPointer,因为new WeatherObserver(getMvpView())
被调用,而BaseViewSubscriber
errorHandlerHelper为null,因为getApplicationCopomnent为null。
由于同样的原因,静态方法AppUtils.isNetworkAvailable()
中也会抛出NullPointer。
当我尝试评论这些行时,测试就可以了。
我的问题是:
AppUtils.isNetworkAvailable()
?如果是的话,是不是因为
这种方法使用PowerMockito Runner @RunWith(PowerMockRunner.class)
?答案 0 :(得分:2)
我是否应该使用Dagger进行单元测试?如果是,请举例说明我的测试。
您不必在测试中使用Dagger,但是依赖注入将使您受益的地方,因为它将帮助您剥离依赖项,并且测试将能够替换它们。
我应该将PowerMockito用于静态方法AppUtils.isNetworkAvailable()吗?如果是,只是因为这种方法使用PowerMockito Runner才行 @RunWith(PowerMockRunner.class)?
静态方法通常不适合测试,因为您无法替换它们(至少不容易和没有PowerMock)以进行测试。
更好的做法是使用Dagger
来生成代码以注入这些依赖项,最好是在Constructor中,因此在测试中,您可以根据测试需求简单地提供这些依赖项(在必要时使用模拟或伪造)。
在您的情况下,您可以将ErrorHandlerHelper
和AppUtils
添加到BaseViewSubscriber
构造函数中。由于BaseViewSubscriber
不应该注入,您需要在演示者中从外部提供这些模块,您应该使用注入来获取这些对象。再次在建设者。
在测试时,只需将此对象替换或提供给演示者,该演示者将把它交给BaseViewSubscriber
。
您可以在android here上阅读有关测试接缝的更多信息。
除此之外,对我来说,Observer
和Disposable
的OO层次结构非常奇怪,它包含Observable以获得共同的行为,它本质上打破了功能流导向的被动方法,您可能需要考虑使用Transformers
等compose这样的模式,并使用doOnXXX运算符在反应流中应用常见行为。