注意:我使用()而不是尖括号
我有一个MVP android应用程序,它使用Retofit2和RxJava2从GitHub Api获取数据。代码运行良好,我能够恢复一个可观察的(响应(列表(头)),其中响应来自Reformation2,头来自OkHttp3。
但是当涉及到单元测试时,我遇到了一个问题:我无法模拟响应(List(Headers))。Retrofit2响应类有一个私有构造函数,所以我无法创建它的实例。然后我尝试使用OkHttp MockWebServer来拥有一个MockACK(List(Headers))。尽管我可以将Headers设置为MockACK实例,但我无法获得MockACK(List(Headers))
我的服务:
@GET("users/{username}/repos")
Observable<Response<List<Headers>>> checkReposPerUser(@Path("username") String owner,
@Query("access_token") String accessTokenString,
@Query("token_type") String accessTokenTypeString,
@Query("per_page") String perPageValue);
我的演示者:
@Override
public void checkRepoPerUser(String owner) {
//recovering access token data from Shared Preferences;
String accessTokenString = repository.getAccessTokenString();
String accessTokenTypeString = repository.getAccessTokenType();
//Asking for a list of repositories with 1 repository per page.
//This let us know how many repositories we found and also to deal with error response code
Disposable disposable = repository.checkReposPerUser(owner, accessTokenString, accessTokenTypeString, "1")
.subscribeOn(ioScheduler)
.observeOn(uiScheduler)
.subscribe(this::handleReturnedHeaderData, this::handleHeaderError);
disposeBag.add(disposable);
}
@VisibleForTesting
public void handleReturnedHeaderData(Response<List<Headers>> response) {
//getting value 'Link' from response headers in order to count the repositories
String link = response.headers().get("Link");
String message = response.message();
//checking GitHub API requests limit
String limit = response.headers().get("X-RateLimit-Limit");
Log.d(TAG, "Limit requests: " + limit);
String limitRemaining = response.headers().get("X-RateLimit-Remaining");
Log.d(TAG, "Limit requests remaining: " + limitRemaining);
//getting http response code
int code = response.code();
switch (code){
case 404:
if(message.equalsIgnoreCase("not found")){ //User not exists
view.showUserNotFoundMessage();
}else{
view.showErrorMessage(message);
}
break;
case 403:
//GitHub API requests limit reached
//Instead of showing an error, we start the login process,
// store another access token in shared Preferences and resend the same request that failed before
view.startLogin();
break;
case 200:
if(link == null){ //Link value is not present into the header, it means there's 0 or 1 repo
Log.d(TAG, "Total repos for current user is 0 or 1.");
//get the repository
searchRepo(view.getOwner()); //Starting looking for data
}else if( link != null){
//get last page number: considering that we requested all the repos paginated with
//only 1 repo per page, the last page number is equal to the total number of repos
String totalRepoString = link.substring(link.lastIndexOf("&page=") + 6, link.lastIndexOf(">"));
Log.d(TAG, "Total repos for current user are " + totalRepoString);
// TODO once we know how many repositories we have, we can decide how many calls to do (total repositories/100 rounded up )
//get the repositories
searchRepo(view.getOwner()); //Starting 3 looking for data
}
break;
default:
searchRepo(view.getOwner()); //Starting 3 looking for data
break;
}
}
现在,我想单元测试句柄返回的HeaderData(Response(List(Headers))响应)。这是测试类:
public class RepositoriesPresenterTest {
private static final Repo REPO1 = new Repo();
private static final Repo REPO2 = new Repo();
private static final Repo REPO3 = new Repo();
private static final List<Repo> NO_REPOS = Collections.emptyList();
private static final List<Repo> THREE_REPOS = Arrays.asList(REPO1, REPO2, REPO3);
public static final String OWNER = "owner";
public static final String ACCESS_TOKEN_STRING = "access_token_string";
public static final String ACCESS_TOKEN_TYPE = "access_token_type";
public static final String PER_PAGE_VALUE = "per_page_value";
@Parameterized.Parameters
public static Object[] data() {
return new Object[] {NO_REPOS, THREE_REPOS};
}
@Parameterized.Parameter
public List<Repo> repos;
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Mock private GitHubChallengeRepository repositoryMock;
@Mock private RepositoriesContract.View viewMock;
@Mock private Response<List<Headers>> responseListHeaders;
private TestScheduler testScheduler;
private RepositoriesPresenter SUT; //System Under Test
@Before public void setUp() {
testScheduler = new TestScheduler();
SUT = new RepositoriesPresenter(repositoryMock, viewMock, testScheduler, testScheduler);
}
}
进入存储库PresenterTest类我尝试过:
@Test public void repoPresenter_CheckRepoPerUser_responseHeadersListExpected() throws Exception {
// Mock a response with status 200 and some Headers
MockResponse mockResponse = new MockResponse()
.setResponseCode(200)
.setBody("{}")
.setHeader("Status", "status_value")
.setHeader("X-RateLimit-Limit", "60")
.setHeader("X-RateLimit-Remaining", "57");
List<Headers> headersList = Arrays.asList(mockResponse.getHeaders());
// Given
given(repositoryMock.getAccessTokenString()).willReturn(ACCESS_TOKEN_STRING);
given(repositoryMock.getAccessTokenType()).willReturn(ACCESS_TOKEN_TYPE);
given(repositoryMock.checkReposPerUser(
OWNER,
ACCESS_TOKEN_STRING,
ACCESS_TOKEN_TYPE,
PER_PAGE_VALUE)).willReturn((Observable<Response<List<Headers>>>) Observable.just(headersList));
// When
SUT.checkRepoPerUser(OWNER);
testScheduler.triggerActions();
// Then
then(viewMock).should().getOwner();
}
但是它不能编译,因为我不能将Observable.just(HeadersList)转换为可观察的(响应(List(Headers)))。
之后,我尝试使用MockWebServer来模拟连接(即使我认为对于测试不是必需的):
@Test
public void repoPresenter_CheckRepoPerUser_responseHeadersListExpected() throws InterruptedException, IOException {
MockWebServer mockWebServer = new MockWebServer();
TestObserver testObserver = new TestObserver<Response<List<Headers>>>();
String path = "\"users/{username}/repos\"";
// Mock a response with status 200 and some Headers
MockResponse mockResponse = new MockResponse()
.setResponseCode(200)
.setBody("{}")
.setHeader("Status", "status_value")
.setHeader("X-RateLimit-Limit", "60")
.setHeader("X-RateLimit-Remaining", "57");
// Enqueue request
mockWebServer.enqueue(mockResponse);
// Call the API
repositoryMock.checkReposPerUser(
OWNER,
ACCESS_TOKEN_STRING,
ACCESS_TOKEN_TYPE,
PER_PAGE_VALUE).subscribe((Consumer<? super Response<List<Headers>>>) Observable.just(Arrays.asList(mockResponse.getHeaders()));
testScheduler.triggerActions();
testObserver.awaitTerminalEvent(2, TimeUnit.SECONDS);
// No errors
testObserver.assertNoErrors();
// Make sure we made the request to the required path
assertEquals("60", mockResponse.getHeaders().get("X-RateLimit-Limit"));
// When
SUT.checkRepoPerUser(OWNER);
testScheduler.triggerActions();
// Then
then(viewMock).should().getOwner();
// Shut down the server. Instances cannot be reused.
mockWebServer.shutdown();
}
但是我得到了一个ClassCastException:
java.lang.ClassCastException: io.reactivex.internal.operators.observable.ObservableJust cannot be cast to io.reactivex.functions.Consumer
是否有任何可行的方法来模拟响应(列表(头)),或者我应该开始考虑改变从endpoint获取数据的方式?
使用改造自己的响应对象创建模拟响应非常简单。正如您所说,构造函数是私有的,但您可以使用静态方法创建成功的响应:
Response<List<Headers>> response = Response.success(headersList);
例如,如果您想创建一个因401错误而失败的响应,您可以这样做:
ResponseBody theBody = ResponseBody.create(MediaType.parse("text/html"), "");
Response<List<Headers>> response = Response.error(401, theBody);
使用 GWT 更轻松地测试异步应用程序 您可能从编写 Ajax 应用程序中获得了极大乐趣,但是对它们执行单元测试却着实让人头痛。 在本文中,Andrew Glover 着手解决 Ajax 的弱点(其中之一),即应对异步 Web 应用程序执行单元测试的固有挑战。 幸运的是,他发现在 Google Web Toolkit 的帮助下,解决这个特殊的代码质量问题要比预想的容易。 Ajax 在近期无疑是 W
我有一个API,我需要从标头中提取信息并进行另一次调用。我已经尝试了许多方法,但似乎无法仅获取标头。没有其他响应。 我尝试过让它返回各种响应对象,例如okhttp3标头,Retrofit标头,HttpHeaders等,但首先获得EOF。 任何人都可以告诉我我需要如何构建我的api调用来获取标头吗?
使用Android Studio进行单元测试 原文链接 : Unit Testing With Android Studio 原文作者 : Rex St John 译文出自 : 开发技术前线 www.devtf.cn 译者 : ZhaoKaiQiang 校对者: zhengxiaopeng 状态 : 校对完 这篇文章介绍了在Android Studio中进行单元测试的基础部分。 很多教程都指导你应
问题内容: 我有一个使用Dagger 2进行依赖注入的Android应用。我还使用了最新的gradle构建工具,该工具允许对单元测试和工具测试使用一个构建变体。我正在我的应用程序中使用,我想对此进行模拟以进行测试。我正在测试的类不使用任何Android东西,因此它们只是常规的Java类。 在我的主要代码中,我在扩展该类的类中定义了a ,但是在单元测试中,我没有使用。我试着定义测试和,但匕首不会产生
我有这样一个简单的课程: 我想为它写一个测试,下面是一个框架: ErrorLogger类中的logger是由StaticLoggerBinder提供的,所以我的问题是-如何让它工作,以便那些检查“1*logger.error(u作为字符串)”可以工作?在ErrorLogger类中,我找不到一种恰当的方式来嘲笑那个记录器。我曾考虑过反射,并以某种方式访问它,此外,mockito注入也有一个想法(但如