I"m given a requirement on how to test HTTP website without UI. Let says, we have a google website search functionalities (Not Web Services) and I need to test it. How to start? Can anyone give some example (JUnit)(Get/Post Method) for me to start this project. I tried reading the official documentation but found nothing about it. Thanks in advance.
You can do it with the following snippet
public class Searcher {
public String search(String searchUrl, String searchWord) throws IOException, URISyntaxException {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
URIBuilder builder = new URIBuilder(searchUrl);
builder.setParameter("search_term", searchWord);
HttpGet request = new HttpGet(builder.build());
HttpResponse httpResponse = httpClient.execute(request);
return convertResponseToString(httpResponse);
}
}
private String convertResponseToString(HttpResponse response) throws IOException {
try (Scanner scanner = new Scanner(response.getEntity().getContent(), "UTF-8")) {
String responseString = scanner.useDelimiter("\\Z").next();
return responseString;
}
}
}
public class SearcherTest {
#Rule
public WireMockRule wireMockRule = new WireMockRule(options().dynamicPort());
#Test
public void searchTest() throws IOException, URISyntaxException {
String searchWord = "something";
String expectedResult = "Your expected result";
stubFor(get(urlPathEqualTo("/search"))
.withQueryParam("search_term", equalTo(searchWord))
.willReturn(aResponse()
.withBody(expectedResult)));
Searcher searcher = new Searcher();
String searchResult = searcher.search("http://localhost:" + wireMockRule.port() + "/search", searchWord);
verify(getRequestedFor(urlPathEqualTo("/search"))
.withQueryParam("search_term", equalTo(searchWord)));
assertEquals(expectedResult, searchResult);
}
}
Related
I have created a cloud function to print greetings like "Hello David!". my function below:
public void service(HttpRequest request, HttpResponse response)
throws IOException {
String name = request.getFirstQueryParameter("name").orElse("world");
try {
JsonElement requestParsed = gson.fromJson(request.getReader(), JsonElement.class);
JsonObject requestJson = null;
if (requestParsed != null && requestParsed.isJsonObject()) {
requestJson = requestParsed.getAsJsonObject();
}
if (requestJson != null && requestJson.has("name")) {
name = requestJson.get("name").getAsString();
}
} catch (JsonParseException e) {
logger.severe("Error parsing JSON: " + e.getMessage());
}
var writer = new PrintWriter(response.getWriter());
writer.printf("Hello %s!", name);
}
I have written a integration test like below:
#BeforeEach
public void setUp() throws IOException {
String baseDir = System.getProperty("user.dir");
emulatorProcess = new ProcessBuilder()
.command("./../gradlew", "alo")
.directory(new File(baseDir))
.start();
}
#AfterEach
public void tearDown() throws IOException {
InputStream stdoutStream = emulatorProcess.getInputStream();
ByteArrayOutputStream stdoutBytes = new ByteArrayOutputStream();
stdoutBytes.write(stdoutStream.readNBytes(stdoutStream.available()));
System.out.println(stdoutBytes.toString(StandardCharsets.UTF_8));
if (emulatorProcess.isAlive()) {
emulatorProcess.destroy();
}
}
#Test
void helloHttp_shouldRunWithFunctionsFramework() throws Throwable {
String functionUrl = BASE_URL + "/helloHttp";
HttpRequest getRequest = HttpRequest.newBuilder().uri(URI.create(functionUrl)).GET().build();
RetryRegistry registry = RetryRegistry.of(RetryConfig.custom()
.maxAttempts(6)
.intervalFunction(IntervalFunction.ofExponentialBackoff(200, 2))
.retryExceptions(IOException.class)
.retryOnResult(body -> body.toString().length() == 0)
.build());
Retry retry = registry.retry("my");
String body = Retry.decorateCheckedSupplier(retry, () -> client.send(
getRequest,
HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)).body()
).apply();
assertThat(body).isEqualTo("Hello world!");
}
So I want to fake a params name in the integration test to pass to my GCP function.
so in my GCP function I can take it like this: name = requestJson.get("name").getAsString();. How do I do it?
I just search it out and the answer is: add post method like this
HttpRequest getRequest = HttpRequest
.newBuilder()
.uri(URI.create(functionUrl))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("{\"name\":\"David\"}"))
.build();
I've these two methods from my MetadataManagement class which I'd like to unit test:
#Override
protected void doPut(final HttpServletRequest request, final HttpServletResponse response,
final MetadataResource resource)
throws IOException {
ServiceCommon.checkRole(getSubject(request));
if (resource.getType() != Type.CONTAINER) {
final String err = "Request not allowed for " + request.getURI();
throw new ServiceApiException(ServiceApiError.METHOD_NOT_ALLOWED, err);
}
final String name = getContainerName(resource);
final ServiceApiMetadata config = getConfig(request, PATH);
final StorageLocation storageLocation = getStorageLocation(conf.getStorageLocation());
if (config.getNotifications() != null) {
checkMethodSupported(id);
checkService(id);
}
}
private ServiceApiMetadata getConfig(final HttpServletRequest request, final String path)
throws IOException {
final Schema schema;
try (final InputStream inStream = this.getClass().getResourceAsStream(path)) {
final JSONObject origSchema = new JSONObject(new JSONTokener(inStream));
if (isGoldStar()) {
origSchema.getJSONObject("properties")
.getJSONObject("notifications")
.getJSONObject("properties")
.getJSONObject("topic")
.put("pattern", "^[0-9A-Za-z-.]*$");
}
schema = SchemaLoader.load(origSchema);
}
final ServiceApiMetadata config;
try (final BufferedReader reader = request.getReader()) {
final JSONObject json = new JSONObject(new JSONTokener(reader));
schema.validate(json);
config = ServiceApiMetadata.read(json);
} catch (final ValidationException e) {
_logger.debug(e.getMessage());
if (e.getLocation().contains("#/properties/notifications")) {
throw new ServiceApiException(ServiceApiError.MALFORMED_NOTIFICATIONS_ERROR,
ServiceApiErrorMessage.MALFORMED_JSON);
} else {
throw new ServiceApiException(ServiceApiError.MALFORMED_JSON);
}
} catch (final JSONException e) {
_logger.debug(e.getMessage());
throw new ServiceApiException(ServiceApiError.MALFORMED_JSON);
}
return config;
}
As I understand it I can not directly call getConfig in my test because the method is private. I believe using reflection is an option but is not advised. Based on that, any test of getConfig should be done through doPut.
What I'm most interested in checking is if getConfig.isGoldStar is true, the origSchema pattern updates to ^[0-9A-Za-z]*$ and if it is false it remains at ^[0-9A-Za-z-._]*$.
To call doPut in my test I will need HttpServletRequest, HttpServletResponse and MetadataResource objects. I'm not sure how I generate these. HttpServletRequest and HttpServletResponse are from javax.servlet.ServletRequest and MetadataResource comes from within my project. It takes HttpServletRequest and an enum as parameters.
How do I do this test? I think I should be OK once I can call the doPut method but I'm struggling to do that.
I have the method:
public HTTPResult get(String url) throws Exception{
try {
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
return new HTTPResult(response.getBody(), response.getStatusCode().value());
}
catch (ResourceAccessException e) {
String responseBody = e.getCause().getMessage();
JSONObject obj = new JSONObject(responseBody);
return new HTTPResult(obj.getString("responseBody"), Integer.parseInt(obj.getString("statusCode")));
}
}
I want to do unit testing for it and i am not sure how to proceed:
public class MockHttpServerTest {
private static final int PORT = 51234;
private static final String baseUrl = "http://localhost:" + PORT;
private MockHttpServer server;
private SimpleHttpResponseProvider responseProvider;
private HttpClient client;
#Before
public void setUp() throws Exception {
responseProvider = new SimpleHttpResponseProvider();
server = new MockHttpServer(PORT, responseProvider);
server.start();
client = new DefaultHttpClient();
}
I am getting RED for MockHttpServer & SimpleHttpResponseProvider which should be part of org.apache.wink.client.*; which i am importing. so why do i have red ones? is there some simple way to unit test it?
HTTPResult return me response code and message.
I wrote a Web API using Apache CXF. When I use HttpServletRequest.getParamter() in a post method, it return null.Here is the code:
#Path("/")
public class TokenService extends DigiwinBaseService {
private static void printRequest(HttpServletRequest httpRequest) {
System.out.println("\n\n Headers");
Enumeration headerNames = httpRequest.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = (String) headerNames.nextElement();
System.out.println(headerName + " = " + httpRequest.getHeader(headerName));
}
System.out.println("\n\n Parameters");
Enumeration params = httpRequest.getParameterNames();
while (params.hasMoreElements()) {
String paramName = (String) params.nextElement();
System.out.println(paramName + " = " + httpRequest.getParameter(paramName));
}
System.out.println("\n\n Row data");
System.out.println(extractPostRequestBody(httpRequest));
}
private static String extractPostRequestBody(HttpServletRequest request) {
if ("POST".equalsIgnoreCase(request.getMethod())) {
Scanner s = null;
try {
s = new Scanner(request.getInputStream(), "UTF-8").useDelimiter("\\A");
} catch (IOException e) {
e.printStackTrace();
}
return s.hasNext() ? s.next() : "null";
}
return "null";
}
#POST
#Consumes("application/x-www-form-urlencoded")
public Response Authorize(#FormParam("param") String param,
#FormParam("param2") String param2,#Context HttpServletRequest httpRequest) throws OAuthSystemException {
printRequest(httpRequest);
System.out.println("param:"+param);
System.out.println("param2:"+param2);
return Response.status(HttpServletResponse.SC_OK).entity("OK").build();
}
}
Here is the test code
public class HttpClientTest {
public static void main(String[] args) throws Exception{
String url4 = "/api/services/Test";
String host = "127.0.0.1";
HttpClient httpClient = new HttpClient();
httpClient.getHostConfiguration().setHost(host, 8080, "http");
HttpMethod method = postMethod(url4);
httpClient.executeMethod(method);
String response = method.getResponseBodyAsString();
System.out.println(response);
}
private static HttpMethod postMethod(String url) throws IOException{
PostMethod post = new PostMethod(url);
post.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=gbk");
NameValuePair[] param = {
new NameValuePair("param","param1"),
new NameValuePair("param2","param2"),} ;
post.setRequestBody(param);
post.releaseConnection();
return post;
}
}
Here is the print out :
Headers
content-type = application/x-www-form-urlencoded;charset=gbk
user-agent = Jakarta Commons-HttpClient/3.1
host = 127.0.0.1:8080
content-length = 26
Parameters
Row data
null
param:param1
param2:param2
Why the Parameters is null? How can i get post params using HttpServletRequest.getParamter()
CXF is consuming the POST data to fill the FormParams.
https://issues.apache.org/jira/browse/CXF-2993
The resolution is "won't fix". In the issue, they suggest to use a MultivaluedMap to recover all params, or use only the HttpServletRequest
Option 1
#POST
#Consumes("application/x-www-form-urlencoded")
public Response Authorize( MultivaluedMap<String, String> parameterMap, #Context HttpServletRequest httpRequest) throws OAuthSystemException {
//parameterMap has your POST parameters
Option 2
#POST
#Consumes("application/x-www-form-urlencoded")
public Response Authorize( #Context HttpServletRequest httpRequest) throws OAuthSystemException {
//httpRequest.getParameterMap() has your POST parameters
I have the following class which contains a hard coded URL that never changes:
public class HttpClient {
private final String DOWNLOAD_URL = "http://original.url.json";
public String readJsonDataFromUrl() throws IOException {
URLConnection urlConnection = getUrlConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuffer content = new StringBuffer();
String readLine = "";
while ((readLine = reader.readLine()) != null) {
content.append(readLine);
}
return content.toString();
}
private URLConnection getUrlConnection() throws IOException {
URL jsonLocator = new URL(DOWNLOAD_URL);
return jsonLocator.openConnection();
}
}
Now imagine that I'd like to expect the IOException in my test. In my opinion, the only way to do that is to rewrite the complete class in a mock object because of the final variable:
public class HttpClientMock extends HttpClient {
private final String DOWNLOAD_URL = "http://wrong.test.url.json";
#Override
public String readJsonDataFromUrl() throws IOException {
URLConnection urlConnection = getUrlConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuffer content = new StringBuffer();
String readLine = "";
while ((readLine = reader.readLine()) != null) {
content.append(readLine);
}
return content.toString();
}
private URLConnection getUrlConnection() throws IOException {
URL jsonLocator = new URL(DOWNLOAD_URL);
URLConnection urlConnection = jsonLocator.openConnection();
return urlConnection;
}
}
But this is somehow far-fetched. If the original methods would be changed, the test results could still be positive because with this attempt, I don't actually test the original class anymore.
How can this be done properly? (I don't want to use a framework just for this one test, so are there any design attempts to solve this in a common way?)
Another spin on Gilbert Le Blanc's suggestion, is to make the HttpClient totally ignorant of the URL by injecting it through the constructor.
public class HttpClient {
private final String url;
public HttpClient(String url) { this.url = url; }
}
You can hard code the URL (or read from a config) somewhere externally to HttpClient and inject it wherever you instantiate the client. Then in your test it will be trivial to inject a bad url.
Thanks to everybody, but I think that Gilbert Le Blanc's solution is the most preferable for that case which looks like this:
The original class:
public class HttpClient {
private final String DOWNLOAD_URL = "http://my.original.json.url";
public String readJsonDataFromUrl() throws IOException {
URLConnection urlConnection = getUrlConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuffer content = new StringBuffer();
String readLine = "";
while ((readLine = reader.readLine()) != null) {
content.append(readLine);
}
return content.toString();
}
private URLConnection getUrlConnection() throws IOException {
URL jsonLocator = new URL(getConnectionString());
return jsonLocator.openConnection();
}
protected String getConnectionString() {
return DOWNLOAD_URL;
}
}
The mock object:
public class HttpClientMock extends HttpClient {
private String downloadUrl = "http://my.original.json.url";
public HttpClientMock() {
super();
}
public HttpClientMock(String downloadUrl) {
this.downloadUrl = downloadUrl;
}
#Override
protected String getConnectionString() {
return downloadUrl;
}
}
And the working tests:
public class HttpClientTest {
private JSONParser jsonParser = new JSONParser();
#Test
public void readJsonDataFromUrlSucceeds() throws IOException, ParseException {
HttpClient httpClient = new HttpClientMock();
String jsonString = httpClient.readJsonDataFromUrl();
JSONObject jsonObject = (JSONObject)jsonParser.parse(jsonString);
assertTrue(jsonObject.size() > 0);
}
#Test(expected = IOException.class)
public void readJsonDataFromMalformedUrlFails() throws IOException, ParseException {
HttpClient httpClient = new HttpClientMock("http://malformed");
httpClient.readJsonDataFromUrl();
}
}