如何在 android (MVP) 上测试 Presenter?
How to test presenter on android (MVP)?
我以前从未创建过单元测试。我计划为我的演示者和数据源创建 UI 测试和单元测试。我在我的应用程序中使用 Retrofit、RxJava 和 Dagger。
这是我到目前为止尝试过的方法
数据源(我的数据源来自API)
public class DataSource implements DataSourceContract {
private static DataSource dataSource;
@Inject
SharedPreferences sharedPreferences;
@Inject
NewsService newsService;
private DataSource(Context context) {
DaggerAppComponent.builder()
.networkModule(new NetworkModule(API_URL))
.appModule(new AppModule(context.getApplicationContext()))
.preferencesModule(new PreferencesModule())
.build()
.inject(this);
}
public static synchronized DataSource getInstance(Context context) {
if(dataSource == null) {
dataSource = new DataSource(context);
}
return dataSource;
}
public String parseError(Throwable e) {
if(e instanceof SocketTimeoutException) {
return ERROR_TIMEOUT;
}
else if(e instanceof SocketException) {
return ERROR_NO_CONNECTION;
}
else {
return ERROR_SERVER;
}
}
@Override
public DisposableObserver<NewsResponse> getNews(final Callback<NewsResponse> callback) {
return newsService.getNews()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<NewsResponse>() {
@Override
public void onNext(NewsResponse value) {
callback.onSuccess(value);
}
@Override
public void onError(Throwable e) {
callback.onFailure(e);
}
@Override
public void onComplete() {
}
});
}
}
主持人
public class MainPresenter implements MainContract.Presenter {
private MainContract.View view;
private DataSource dataSource;
private Disposable dispossable;
public MainPresenter(MainContract.View view, DataSource dataSource) {
this.view = view;
this.dataSource = dataSource;
}
@Override
public void onStart() {
getNews();
}
@Override
public void onStop() {
if(dispossable != null && !dispossable.isDisposed()) {
dispossable.dispose();
}
}
@Override
public void getNews() {
view.setLoading(true);
dispossable = dataSource.getNews(new DataSourceContract.Callback<NewsResponse>() {
@Override
public void onSuccess(NewsResponse responseData) {
try {
switch (responseData.getStatus()) {
case API_SUCCESS:
view.setLoading(false);
view.getNewsSuccess(responseData.getArticles());
break;
default:
view.setLoading(false);
view.getNewsFailed(responseData.getStatus());
break;
}
}
catch (Exception e) {
view.setLoading(false);
view.getNewsFailed(ERROR_SERVER);
}
}
@Override
public void onFailure(Throwable e) {
view.setLoading(false);
view.isNetworkFailed(dataSource.parseError(e), false);
}
});
}
}
这是对我的主持人的测试
public class MainPresenterTest {
@Mock
DataSource dataSource;
@Mock
MainContract.View view;
MainContract.Presenter presenter;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
presenter = new MainPresenter(view, dataSource);
}
@Test
public void getNews() throws Exception {
List<Article> articleList = new ArrayList<>();
presenter.getNews();
Mockito.verify(view, Mockito.only()).getNewsSuccess(articleList);
}
}
但是我运行测试的时候出现错误
Wanted but not invoked:
view.getNewsSuccess([]);
-> at com.java.mvp.view.main.MainPresenterTest.getNews(MainPresenterTest.java:37)
我没问题运行在设备上安装这个应用程序,但我无法让它在测试中运行
知道如何解决这个演示者测试吗?我做对了吗?
以及如何测试我的数据源?我不知道如何测试这个
谢谢
你也必须模拟 :
dataSource.getNews() 在 :
时使用 Mockito
例如
when(dataSource.getNews()).thenReturn(new SuccessCallback());
所以你必须将你的测试代码引入成功回调并检查那里调用了哪些方法。
eroor 的情况也是如此。
保持简单。您正在测试您的演示者,而不是数据源。向演示者添加新方法以获取成功和错误响应。然后添加两个测试:一个用于成功,一个用于错误。
@Override
public void getNews() {
view.setLoading(true);
dispossable = dataSource.getNews(new DataSourceContract.Callback<NewsResponse>() {
@Override
public void onSuccess(NewsResponse responseData) {
onSuccessNewsResponse(responseData);
}
@Override
public void onFailure(Throwable e) {
onErrorNewsResponse(e);
}
});
}
向新方法添加 @VisibleForTesting
注释。
成功测试:
@Test
public void getNewsSuccess() {
presenter.onSuccessNewsResponse(your_response);
Mockito.verify(...);
}
错误测试:
@Test
public void getNewsError() {
presenter.onErrorNewsResponse(your_error);
Mockito.verify(...);
}
我以前从未创建过单元测试。我计划为我的演示者和数据源创建 UI 测试和单元测试。我在我的应用程序中使用 Retrofit、RxJava 和 Dagger。
这是我到目前为止尝试过的方法
数据源(我的数据源来自API)
public class DataSource implements DataSourceContract {
private static DataSource dataSource;
@Inject
SharedPreferences sharedPreferences;
@Inject
NewsService newsService;
private DataSource(Context context) {
DaggerAppComponent.builder()
.networkModule(new NetworkModule(API_URL))
.appModule(new AppModule(context.getApplicationContext()))
.preferencesModule(new PreferencesModule())
.build()
.inject(this);
}
public static synchronized DataSource getInstance(Context context) {
if(dataSource == null) {
dataSource = new DataSource(context);
}
return dataSource;
}
public String parseError(Throwable e) {
if(e instanceof SocketTimeoutException) {
return ERROR_TIMEOUT;
}
else if(e instanceof SocketException) {
return ERROR_NO_CONNECTION;
}
else {
return ERROR_SERVER;
}
}
@Override
public DisposableObserver<NewsResponse> getNews(final Callback<NewsResponse> callback) {
return newsService.getNews()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<NewsResponse>() {
@Override
public void onNext(NewsResponse value) {
callback.onSuccess(value);
}
@Override
public void onError(Throwable e) {
callback.onFailure(e);
}
@Override
public void onComplete() {
}
});
}
}
主持人
public class MainPresenter implements MainContract.Presenter {
private MainContract.View view;
private DataSource dataSource;
private Disposable dispossable;
public MainPresenter(MainContract.View view, DataSource dataSource) {
this.view = view;
this.dataSource = dataSource;
}
@Override
public void onStart() {
getNews();
}
@Override
public void onStop() {
if(dispossable != null && !dispossable.isDisposed()) {
dispossable.dispose();
}
}
@Override
public void getNews() {
view.setLoading(true);
dispossable = dataSource.getNews(new DataSourceContract.Callback<NewsResponse>() {
@Override
public void onSuccess(NewsResponse responseData) {
try {
switch (responseData.getStatus()) {
case API_SUCCESS:
view.setLoading(false);
view.getNewsSuccess(responseData.getArticles());
break;
default:
view.setLoading(false);
view.getNewsFailed(responseData.getStatus());
break;
}
}
catch (Exception e) {
view.setLoading(false);
view.getNewsFailed(ERROR_SERVER);
}
}
@Override
public void onFailure(Throwable e) {
view.setLoading(false);
view.isNetworkFailed(dataSource.parseError(e), false);
}
});
}
}
这是对我的主持人的测试
public class MainPresenterTest {
@Mock
DataSource dataSource;
@Mock
MainContract.View view;
MainContract.Presenter presenter;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
presenter = new MainPresenter(view, dataSource);
}
@Test
public void getNews() throws Exception {
List<Article> articleList = new ArrayList<>();
presenter.getNews();
Mockito.verify(view, Mockito.only()).getNewsSuccess(articleList);
}
}
但是我运行测试的时候出现错误
Wanted but not invoked:
view.getNewsSuccess([]);
-> at com.java.mvp.view.main.MainPresenterTest.getNews(MainPresenterTest.java:37)
我没问题运行在设备上安装这个应用程序,但我无法让它在测试中运行
知道如何解决这个演示者测试吗?我做对了吗?
以及如何测试我的数据源?我不知道如何测试这个
谢谢
你也必须模拟 :
dataSource.getNews() 在 :
时使用 Mockito例如
when(dataSource.getNews()).thenReturn(new SuccessCallback());
所以你必须将你的测试代码引入成功回调并检查那里调用了哪些方法。 eroor 的情况也是如此。
保持简单。您正在测试您的演示者,而不是数据源。向演示者添加新方法以获取成功和错误响应。然后添加两个测试:一个用于成功,一个用于错误。
@Override
public void getNews() {
view.setLoading(true);
dispossable = dataSource.getNews(new DataSourceContract.Callback<NewsResponse>() {
@Override
public void onSuccess(NewsResponse responseData) {
onSuccessNewsResponse(responseData);
}
@Override
public void onFailure(Throwable e) {
onErrorNewsResponse(e);
}
});
}
向新方法添加 @VisibleForTesting
注释。
成功测试:
@Test
public void getNewsSuccess() {
presenter.onSuccessNewsResponse(your_response);
Mockito.verify(...);
}
错误测试:
@Test
public void getNewsError() {
presenter.onErrorNewsResponse(your_error);
Mockito.verify(...);
}