Skip to content

Commit 2c87f82

Browse files
committed
Refactor unit test for Rest services.
1 parent 3cb9f53 commit 2c87f82

3 files changed

Lines changed: 216 additions & 51 deletions

File tree

‎AndroidAnnotations/functional-test-1-5-tests/src/test/java/org/androidannotations/test15/rest/MyServiceTest.java‎

Lines changed: 56 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.Map;
2828

2929
import org.androidannotations.test15.AndroidAnnotationsTestRunner;
30+
import org.androidannotations.test15.rest.RequestTestBuilder.RequestTestBuilderExecutor;
3031
import org.apache.http.Header;
3132
import org.apache.http.message.BasicHeader;
3233
import org.junit.Test;
@@ -49,16 +50,16 @@ public class MyServiceTest {
4950
private void addPendingResponse(String jsonResponse) {
5051
addPendingResponse(jsonResponse, "_=_");
5152
}
53+
5254
private void addPendingResponse(String jsonResponse, String... cookies) {
53-
Header[] headers = new Header[1 + cookies.length/2];
55+
Header[] headers = new Header[1 + cookies.length / 2];
5456
headers[0] = new BasicHeader("content-type", "application/json");
55-
for (int i=0, j=1; i < cookies.length-1; i += 2, j++) {
56-
headers[j] = new BasicHeader("set-cookie", cookies[i] + "=" + cookies[i+1]);
57+
for (int i = 0, j = 1; i < cookies.length - 1; i += 2, j++) {
58+
headers[j] = new BasicHeader("set-cookie", cookies[i] + "=" + cookies[i + 1]);
5759
}
5860
Robolectric.addPendingHttpResponse(HttpStatus.OK.value(), jsonResponse.replaceAll("'", "\""), headers);
5961
}
6062

61-
6263
@Test
6364
public void can_override_root_url() {
6465
MyService_ myService = new MyService_();
@@ -164,46 +165,45 @@ public void urlWithAParameterDeclaredTwiceTest() {
164165

165166
Event event1 = new Event(1, "event1");
166167
Event event2 = new Event(2, "event2");
167-
Event[][] events = new Event[][] {{event1, event2}, {event1, event2}};
168+
Event[][] events = new Event[][] { { event1, event2 }, { event1, event2 } };
168169

169-
for (int i = 0 ; i < events.length ; i++) {
170+
for (int i = 0; i < events.length; i++) {
170171

171172
assertEquals(results[i].length, events[i].length);
172173

173-
for (int j = 0 ; j < events[i].length ; j++) {
174+
for (int j = 0; j < events[i].length; j++) {
174175
assertEquals(events[i][j].getName(), results[i][j].getName());
175176
assertEquals(events[i][j].getId(), results[i][j].getId());
176177
}
177178
}
178179
}
179-
180+
180181
@Test
181182
public void manualFullUrl() {
182-
183+
183184
MyService_ myService = new MyService_();
184185

185186
RestTemplate restTemplate = mock(RestTemplate.class);
186187
myService.setRestTemplate(restTemplate);
187188

188189
// make sure we used the full custom url.
189190
// this may be used like in Google's APIs
190-
// to fetch an oauth token; Mockito doesn't
191-
// return a response with the mock'd template,
192-
// so we just use this weird "ping" endpoint
191+
// to fetch an oauth token; Mockito doesn't
192+
// return a response with the mock'd template,
193+
// so we just use this weird "ping" endpoint
193194
addPendingResponse("fancyHeaderToken");
194195
myService.setHttpBasicAuth("fancyUser", "fancierPassword");
195196
myService.ping();
196197
verify(restTemplate).exchange(eq("http://company.com/client/ping"), Mockito.<HttpMethod> any(), Mockito.<HttpEntity<?>> any(), Mockito.<Class<Object>> any());
197198
}
198-
199+
199200
@Test
200201
public void cookieInUrl() {
201-
202202
final String xtValue = "1234";
203203
final String sjsaidValue = "7890";
204204
final String locationValue = "somePlace";
205205
final int yearValue = 2013;
206-
206+
207207
MyService_ myService = new MyService_();
208208

209209
RestTemplate restTemplate = mock(RestTemplate.class);
@@ -212,13 +212,13 @@ public void cookieInUrl() {
212212
addPendingResponse("{'id':1,'name':'event1'}");
213213

214214
// normally this is set by a call like authenticate()
215-
// which is annotated with @SetsCookie
215+
// which is annotated with @SetsCookie
216216
myService.setCookie("xt", xtValue);
217217
myService.setCookie("sjsaid", sjsaidValue);
218218
myService.setHttpBasicAuth("fancyUser", "fancierPassword");
219219
myService.getEventsVoid(locationValue, yearValue);
220220

221-
ArgumentMatcher<HttpEntity<Void>> matcher = new ArgumentMatcher<HttpEntity<Void>>() {
221+
ArgumentMatcher<HttpEntity<Void>> matcher = new ArgumentMatcher<HttpEntity<Void>>() {
222222

223223
@Override
224224
public boolean matches(Object argument) {
@@ -235,34 +235,46 @@ public boolean matches(Object argument) {
235235
}
236236

237237
@Test
238-
public void authenticatedRequests() {
239-
String xtValue = "1234";
240-
String sjsaidValue = "5678";
241-
242-
final String fancyHeaderName = "SomeFancyHeader";
243-
final String fancyToken = "fancyHeaderToken";
244-
myService.setHeader(fancyHeaderName, fancyToken);
245-
246-
addPendingResponse("[]", "xt", xtValue, "sjsaid", sjsaidValue);
247-
myService.authenticate();
248-
249-
assertEquals(xtValue, myService.getCookie("xt"));
250-
assertEquals(sjsaidValue, myService.getCookie("sjsaid"));
251-
252-
RestTemplate restTemplate = mock(RestTemplate.class);
253-
myService.setRestTemplate(restTemplate);
238+
public void authenticate() {
239+
RequestTestBuilder.build() //
240+
.requestHeader("SomeFancyHeader", "aFancyHeader") //
241+
.responseCookie("xt", "1234") //
242+
.responseCookie("sjsaid", "5678") //
243+
.asserts(new RequestTestBuilderExecutor() {
244+
@Override
245+
public void execute(MyService myService) {
246+
myService.authenticate();
247+
}
248+
});
249+
}
254250

255-
// deletes
256-
ArgumentMatcher<HttpEntity<Void>> matcher = new ArgumentMatcher<HttpEntity<Void>>() {
251+
@Test
252+
public void removeEventWithRequires() {
253+
RequestTestBuilder.build() //
254+
.requestCookie("myCookie", "myCookieValue") //
255+
.requestHeader("SomeFancyHeader", "aFancyHeader") //
256+
.hasUrlVariables(true) //
257+
.asserts(new RequestTestBuilderExecutor() {
258+
@Override
259+
public void execute(MyService myService) {
260+
myService.removeEventWithRequires(0);
261+
}
262+
});
263+
}
257264

258-
@Override
259-
public boolean matches(Object argument) {
260-
final String expected = fancyToken;
261-
return expected.equals(((HttpEntity<?>) argument).getHeaders().get(fancyHeaderName).get(0));
262-
}
263-
};
264-
addPendingResponse("");
265-
myService.removeEventWithRequires(0);
266-
verify(restTemplate).exchange(Mockito.anyString(), eq(HttpMethod.DELETE), argThat(matcher), Mockito.<Class<Object>> any(), Mockito.<Map<String, ?>> any());
265+
@Test
266+
public void updateEventWithRequires() {
267+
RequestTestBuilder.build() //
268+
.requestCookie("myCookie", "myCookieValue") //
269+
.requestHeader("SomeFancyHeader", "aFancyHeader") //
270+
.responseContent("{'id':1,'name':'event1'}") //
271+
.hasUrlVariables(true) //
272+
.asserts(new RequestTestBuilderExecutor() {
273+
@Override
274+
public void execute(MyService myService) {
275+
myService.updateEventWithRequires(0);
276+
}
277+
});
267278
}
279+
268280
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
package org.androidannotations.test15.rest;
2+
3+
import static org.mockito.Matchers.argThat;
4+
import static org.mockito.Mockito.verify;
5+
6+
import java.util.Arrays;
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
import java.util.Set;
10+
11+
import junit.framework.AssertionFailedError;
12+
13+
import org.apache.http.Header;
14+
import org.apache.http.message.BasicHeader;
15+
import org.mockito.ArgumentMatcher;
16+
import org.mockito.Mockito;
17+
import org.springframework.http.HttpEntity;
18+
import org.springframework.http.HttpHeaders;
19+
import org.springframework.http.HttpMethod;
20+
import org.springframework.http.HttpStatus;
21+
import org.springframework.web.client.RestTemplate;
22+
23+
import com.xtremelabs.robolectric.Robolectric;
24+
25+
public class RequestTestBuilder {
26+
private MyService_ myService = new MyService_();
27+
private HttpEntityArgumentMatcher entityArgumentMatcher = new HttpEntityArgumentMatcher();;
28+
private RestTemplate restTemplate;
29+
30+
private Map<String, String> requestHeaders = new HashMap<String, String>();
31+
private Map<String, String> requestCookies = new HashMap<String, String>();
32+
private Map<String, String> responseCookies = new HashMap<String, String>();
33+
private String responseContent;
34+
private boolean hasUrlVariables;
35+
36+
public static RequestTestBuilder build() {
37+
return new RequestTestBuilder();
38+
}
39+
40+
public RequestTestBuilder() {
41+
restTemplate = Mockito.spy(myService.getRestTemplate());
42+
myService.setRestTemplate(restTemplate);
43+
}
44+
45+
public RequestTestBuilder requestHeader(String name, String value) {
46+
requestHeaders.put(name, value);
47+
myService.setHeader(name, value);
48+
return this;
49+
}
50+
51+
public RequestTestBuilder requestCookie(String name, String value) {
52+
requestCookies.put(name, value);
53+
myService.setCookie(name, value);
54+
return this;
55+
}
56+
57+
public RequestTestBuilder responseCookie(String name, String value) {
58+
responseCookies.put(name, value);
59+
return this;
60+
}
61+
62+
public RequestTestBuilder responseContent(String responseContent) {
63+
this.responseContent = responseContent;
64+
return this;
65+
}
66+
67+
public RequestTestBuilder hasUrlVariables(boolean hasUrlVariables) {
68+
this.hasUrlVariables = hasUrlVariables;
69+
return this;
70+
}
71+
72+
public void asserts(RequestTestBuilderExecutor executor) {
73+
// Prepare fake response
74+
prepareFakeResponse();
75+
76+
// Make the call
77+
executor.execute(myService);
78+
79+
// Checks
80+
checkRequest();
81+
checkResponseCookies();
82+
}
83+
84+
private void prepareFakeResponse() {
85+
Set<String> cookiesNames = responseCookies.keySet();
86+
Header[] headers = new Header[1 + responseCookies.size()];
87+
headers[0] = new BasicHeader("content-type", "application/json");
88+
89+
int i = 1;
90+
for (String cookieName : cookiesNames) {
91+
headers[i++] = new BasicHeader("Set-Cookie", cookieName + "=" + responseCookies.get(cookieName));
92+
}
93+
94+
String responseBody = responseContent != null ? responseContent.replaceAll("'", "\"") : "";
95+
96+
Robolectric.addPendingHttpResponse(HttpStatus.OK.value(), responseBody, headers);
97+
}
98+
99+
private void checkRequest() {
100+
if (hasUrlVariables) {
101+
verify(restTemplate).exchange(Mockito.anyString(), //
102+
Mockito.any(HttpMethod.class), //
103+
argThat(entityArgumentMatcher), //
104+
Mockito.<Class<Object>> any(),//
105+
Mockito.<Map<String, Object>> any());
106+
} else {
107+
verify(restTemplate).exchange(Mockito.anyString(), //
108+
Mockito.any(HttpMethod.class), //
109+
argThat(entityArgumentMatcher), //
110+
Mockito.<Class<Object>> any());
111+
}
112+
}
113+
114+
private void checkResponseCookies() throws AssertionFailedError {
115+
for (String responseCookieName : responseCookies.keySet()) {
116+
String cookieValue = myService.getCookie(responseCookieName);
117+
if (cookieValue == null || !cookieValue.equals(responseCookies.get(responseCookieName)))
118+
throw new AssertionFailedError("Response cookie " + responseCookieName + " wasn't set");
119+
}
120+
}
121+
122+
public class HttpEntityArgumentMatcher extends ArgumentMatcher<HttpEntity<Void>> {
123+
@Override
124+
public boolean matches(Object argument) {
125+
HttpEntity<?> httpEntity = (HttpEntity<?>) argument;
126+
HttpHeaders httpHeaders = httpEntity.getHeaders();
127+
128+
// Check that cookies set earlier are sent in the request
129+
if (requestCookies.size() > 0) {
130+
String[] httpCookies = httpHeaders.getFirst("Cookie").split(";");
131+
for (String cookieName : requestCookies.keySet()) {
132+
if (Arrays.binarySearch(httpCookies, cookieName + "=" + requestCookies.get(cookieName)) == -1)
133+
throw new AssertionFailedError("The cookie " + cookieName + " is missing!");
134+
}
135+
}
136+
137+
// Check that headers set earlier are sent in the request
138+
for (String headerName : requestHeaders.keySet()) {
139+
if (!(httpHeaders.containsKey(headerName) && httpHeaders.getFirst(headerName).equals(requestHeaders.get(headerName))))
140+
throw new AssertionFailedError("The header " + headerName + " is missing!");
141+
}
142+
143+
return true;
144+
}
145+
}
146+
147+
public interface RequestTestBuilderExecutor {
148+
void execute(MyService myService);
149+
}
150+
151+
}

‎AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/rest/MyService.java‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ public interface MyService {
5858
@Accept("application/json")
5959
Event[] getEventsArray(String location, int year);
6060

61-
6261
@Get("/events/{year}/{year}")
6362
@Accept(MediaType.APPLICATION_JSON)
6463
Event[][] urlWithAParameterDeclaredTwice(int year);
@@ -72,16 +71,13 @@ public interface MyService {
7271
/*
7372
* You may (or may not) declare throwing RestClientException (as a reminder, since it's a RuntimeException), but nothing else.
7473
*/
75-
ResponseEntity<EventList> getEvents2(String location, int year)
76-
throws RestClientException;
74+
ResponseEntity<EventList> getEvents2(String location, int year) throws RestClientException;
7775

7876
@Get("/events/{year}/{location}")
79-
ResponseEntity<Event[]> getEventsArray2(String location, int year)
80-
throws RestClientException;
77+
ResponseEntity<Event[]> getEventsArray2(String location, int year) throws RestClientException;
8178

8279
@Get("/events/{year}/{location}")
83-
ResponseEntity<Event[][]> getEventsArrayOfArrays2(String location, int year)
84-
throws RestClientException;
80+
ResponseEntity<Event[][]> getEventsArrayOfArrays2(String location, int year) throws RestClientException;
8581

8682
@Get("/events/{year}/{location}")
8783
List<Event> getEventsGenericsList(String location, int year) throws RestClientException;
@@ -198,6 +194,12 @@ ResponseEntity<Event[][]> getEventsArrayOfArrays2(String location, int year)
198194
@Put("/events/{date}")
199195
Event updateEventWithResponse(long date);
200196

197+
@Put("/events/{date}")
198+
@RequiresHeader("SomeFancyHeader")
199+
@RequiresCookie("myCookie")
200+
@RequiresCookieInUrl("myCookieInUrl")
201+
Event updateEventWithRequires(long date);
202+
201203
// *** DELETE ***
202204

203205
@Delete("/events/{id}")

0 commit comments

Comments
 (0)