I'm trying to create a test fixture using Fitnesse framework, and I want to test a function which retrieves data from a server (RESTFUL service). My test case is very simple:
public class FriendListActivityFixture extends ColumnFixture {
public int URL;
public String test() {
JSONArray array = JsonHelper.getJsonArrayFromUrl("http://107.22.209.62/android/get_users.php");
return array.toString();
}
}
public static JSONArray getJsonArrayFromUrl(String url) {
InputStream input = null;
String result = "";
JSONArray jsonArray = null;
try {
HttpClient httpclient = CustomHttpClient.getHttpClient();
HttpPost httppost = new HttpPost(url);
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
input = entity.getContent();
}
catch (Exception e) {
Log.e(TAG + ".getJsonArrayFromUrl(String url)", "Error in http connection " + e.toString());
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "iso-8859-1"), 8);
StringBuilder content = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
content.append(line + "\n");
}
input.close();
result = content.toString();
}
catch (Exception e) {
Log.e(TAG + ".getJsonArrayFromUrl(String url)", "Error parsing result " + e.toString());
}
try {
jsonArray = new JSONArray(result);
}
catch (JSONException e) {
Log.e(TAG + "getJsonArrayFromUrl(String url)", "Error converting data " + e.toString());
}
return jsonArray;
}
And here is the Fitnesse test page:!path fitnesse.jar
!path C:\Program Files (x86)\Android\android-sdk\platforms\android-10\android.jar
!path C:\Users\chan\git\Spotr\Spotr\bin\classes
!|com.csun.spotr.fitnesse.FriendListActivityFixture|
|URL|test?|
|0|"wwa"|
Since it's just a demo, my test might look a bit silly at the moment. Unfortunately, I keep getting these errors:
java.lang.RuntimeException: Stub!
at android.util.Log.e(Log.java:15)
at com.csun.spotr.util.JsonHelper.getJsonArrayFromUrl(JsonHelper.java:75)
at com.csun.spotr.fitnesse.FriendListActivityFixture.test(FriendListActivityFixture.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at fit.TypeAdapter.invoke(TypeAdapter.java:109)
at fit.TypeAdapter.get(TypeAdapter.java:97)
at fit.Fixture$CellComparator.compareCellToResult(Fixture.java:371)
at fit.Fixture$CellComparator.access$100(Fixture.java:357)
at fit.Fixture.compareCellToResult(Fixture.java:299)
at fit.Fixture.check(Fixture.java:295)
at fit.ColumnFixture.check(ColumnFixture.java:51)
at fit.Binding$QueryBinding.doCell(Binding.java:215)
at fit.ColumnFixture.doCell(ColumnFixture.java:37)
at fit.Fixture.doCells(Fixture.java:171)
at fit.Fixture.doRow(Fixture.java:165)
at fit.ColumnFixture.doRow(ColumnFixture.java:25)
at fit.Fixture.doRows(Fixture.java:159)
at fit.ColumnFixture.doRows(ColumnFixture.java:18)
at fit.Fixture.doTable(Fixture.java:153)
at fit.Fixture.interpretTables(Fixture.java:99)
at fit.Fixture.doTables(Fixture.java:79)
at fit.FitServer.process(FitServer.java:81)
at fit.FitServer.run(FitServer.java:56)
at fit.FitServer.main(FitServer.java:41)
And I have no idea what is it telling me? I wrote other testing method like add(), substract(), everything worked fine. I wonder does this error involve running a long task on the main thread? Any idea?
android.jar contains only stub implementation of the classes. It provides the means for you app to build, once you have your APK you must run it on an android device or emulator.
If I'm not wrong you are trying to run on host's JVM.
You can fix this problem and test within your IDE really easily by using Roboelectric.
As dtmilano said, you can't run Android code on your laptop as is, but Roboelectric basically substitutes the actual method implementations for the stubs in Android.jar.
Two things to watch out for if you go with this solution:
Make sure that your JAR import is above the Android JAR in your dependencies list if using IntelliJ
It defaults to blocking HTTP requests under the assumption that you don't actually want to change the state of a server somewhere. You can, however, disable this quite easily: Roboelectric.getFakeHttpLayer().interceptHttpRequests(false);
As mentioned previously, Android jars are not good for anything beyond compiling. Even most innocent things are stubbed out completely. But you can still use them in host VM unit tests with good mocking frameworks. My choice is jmockit:
Not sure whether it will work with Fitnesse though
I had this same issue because of the "static" declaration. In my case, .build() caused the issue in a static variable. The simple solution was to not declare the variable static. It can be final. Try removing "static" from the getJsonArrayFromUrl method and see if it works.
Related
I have some experience in Android application development. Now we developed an Android application where we need the exact date and time from Google or the internet. Already I test some code from Stack Overflow and from some other sites, but it did not work correctly. The app crashed. Can anyone help me?
Try this:
private long getTime() throws Exception {
String url = "https://time.is/Unix_time_now";
Document doc = Jsoup.parse(new URL(url).openStream(), "UTF-8", url);
String[] tags = new String[] {
"div[id=time_section]",
"div[id=clock0_bg]"
};
Elements elements= doc.select(tags[0]);
for (int i = 0; i <tags.length; i++) {
elements = elements.select(tags[i]);
}
return Long.parseLong(elements.text() + "000");
}
Gradle:
compile 'org.jsoup:jsoup:1.10.2'
This is enough to get what you wanted:
Using the HttpGet, Client and Response, I manage to get a server's current time from the response Date Header. I can call this all the times I want and will get confident responses (Google is almost 100% available and I can trust on getting correct Date and Time)
try{
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = httpclient.execute(new HttpGet("https://google.com/"));
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpStatus.SC_OK){
String dateStr = response.getFirstHeader("Date").getValue();
//Here I do something with the Date String
System.out.println(dateStr);
} else{
//Closes the connection.
response.getEntity().getContent().close();
throw new IOException(statusLine.getReasonPhrase());
}
}catch (ClientProtocolException e) {
Log.d("Response", e.getMessage());
}catch (IOException e) {
Log.d("Response", e.getMessage());
}
ou can get time from internet time servers using the below program
import java.io.IOException;
import org.apache.commons.net.time.TimeTCPClient;
public final class GetTime {
public static final void main(String[] args) {
try {
TimeTCPClient client = new TimeTCPClient();
try {
// Set timeout of 60 seconds
client.setDefaultTimeout(60000);
// Connecting to time server
// Other time servers can be found at : http://tf.nist.gov/tf-cgi/servers.cgi#
// Make sure that your program NEVER queries a server more frequently than once every 4 seconds
client.connect("nist.time.nosc.us");
System.out.println(client.getDate());
} finally {
client.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.You would need Apache Commons Net library for this to work. Download the library and add to your project build path.
(Or you can also use the trimmed Apache Commons Net Library here : https://www.dropbox.com/s/bjxjv7phkb8xfhh/commons-net-3.1.jar. This is enough to get time from internet )
2.Run the program. You will get the time printed on your console.
I have an Android app where the main part of the app is the APIcalls.java class where I make http requests to get data from server an display the data in the app.
I wanted to create unit test for this Java class since it's the most part of the app. Here is the method for getting the data from server:
StringBuilder sb = new StringBuilder();
try {
httpclient = new DefaultHttpClient();
Httpget httpget = new HttpGet(url);
HttpEntity entity = null;
try {
HttpResponse response = httpclient.execute(httpget);
entity = response.getEntity();
} catch (Exception e) {
Log.d("Exception", e);
}
if (entity != null) {
InputStream is = null;
is = entity.getContent();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
reader.close();
} catch (IOException e) {
throw e;
} catch (RuntimeException e) {
httpget.abort();
throw e;
} finally {
is.close();
}
httpclient.getConnectionManager().shutdown();
}
} catch (Exception e) {
Log.d("Exception", e);
}
String result = sb.toString().trim();
return result;
I thought I can make simple API calls from the tests like this:
api.get("www.example.com")
But every time I make some http calls from the tests, I get an error:
Unexpected HTTP call GET
I know I am doing something wrong here, but can anyone tell me how can I properly test this class in Android?
Thank you for all your answers but I found what I was looking for.
I wanted to test real HTTP calls.
By adding Robolectric.getFakeHttpLayer().interceptHttpRequests(false);
you tell Robolectric not to intercept these requests and it allows you to make real HTTP calls
Robolectric provides some helper methods to mock http response for DefaultHttpClient. If you use DefaultHttpClient without using those methods, you would get a warning message.
Here is an example of how to mock http response:
#RunWith(RobolectricTestRunner.class)
public class ApiTest {
#Test
public void test() {
Api api = new Api();
Robolectric.addPendingHttpResponse(200, "dummy");
String responseBody = api.get("www.example.com");
assertThat(responseBody, is("dummy"));
}
}
You can find more examples by looking at Robolectric's test codes.
I answered another version of this same question, but...
What you have here is not using anything from Android, so Robolectric is basically irrelevant. This is all standard Java and the Apache HTTP library. You simply need a mocking framework and dependency injection to simulate the HttpClient (see my other answer for links). It doesn't have network access while unit testing, and so it fails.
When testing classes that use parts of the Android framework, you can use Robolectric (or similar) to mock or simulate Android.jar since your unit testing framework isn't going to have access to that either.
Let me explain my situation, I developed a complete backend for an Android application in Symfony2.1 that works perfectly, now I'm trying to create the Android app part, for that I created a firewall with http_basic authentication that ensures that my users are correctly authenticated and authorized, I actually can use my app and be logged, but if I try to retrieve any page behind the firewall a get a 404 error.
I don't want to use any external bundle, I just want to send my user/pass on every request since my app makes just three httpclient calls but I don't know hoy to get access granted on every request.
Here is part of my code, feel free to ask :)
Thanks in advance!
My Android http call:
#Override protected String doInBackground(Void... arg0) {
HttpClient httpClient = new DefaultHttpClient();
// construir peticion get
HttpGet httpGet = new HttpGet("http://www.somewebsite.com/api/login/");
httpGet.addHeader(BasicScheme.authenticate(
new UsernamePasswordCredentials(loguser, passw), "UTF-8",
false));
try {
response = httpClient.execute(httpGet);
reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
builder = new StringBuilder();
for(String line = null; (line = reader.readLine()) != null;){
builder.append(line).append("\n");
}
} catch (Exception e) {
e.printStackTrace();
alert("Error de protocolo", "Lo sentimos, ha ocurrido un error");
}
return builder.toString();
}
My firewall
api:
pattern: ^/api/.*
provider: app_user
http_basic:
realm: "API"
access_control:
- { path: ^/api-registro/, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/.*, role: ROLE_API }
providers:
app_user:
entity: { class: Alood\BackBundle\Entity\Usuario, property: user }
encoders:
Alood\BackBundle\Entity\Usuario: plaintext
My Controller
public function apiLoginAction()
{
$peticion = $this->getRequest();
$sesion = $peticion->getSession();
$usuario = $this->get('security.context')->getToken()->getUser();
$error = $peticion->attributes->get(SecurityContext::AUTHENTICATION_ERROR,
$sesion->get(SecurityContext::AUTHENTICATION_ERROR));
$securityContext = $this->container->get('security.context');
if( $securityContext->isGranted('IS_AUTHENTICATED_FULLY')){
$texto["user"] = $usuario->getUser();
return new JsonResponse($texto);
}
}
Note: If I repeat the same steps in a different function of my controller I get a problem in my android app and I don't know how to solve this.
It happened to be a typo issue in my routing.yml so if its useful for somebody I must say this works properly.
I am using the Jackson JSON parser as I heard it was a lot more efficient than the default Android parser. I learned how to use it off this tutorial here
http://www.mkyong.com/java/jackson-streaming-api-to-read-and-write-json/
which is great tutorial if anyone wants to learn how to use Jackson json parser.
However, I am having an issue in that I can parse data fine in Java from a URL, however when I use Jackson with Android, I get null values or the screen just shows up black for some reason.
In order to retrieve the data from the website I am using this code from here
http://www.javacodegeeks.com/2011/01/android-json-parsing-gson-tutorial.html
private InputStream retrieveStream(String url) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet getRequest = new HttpGet(url);
try {
HttpResponse getResponse = client.execute(getRequest);
final int statusCode = getResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w(getClass().getSimpleName(),
"Error " + statusCode + " for URL " + url);
return null;
}
HttpEntity getResponseEntity = getResponse.getEntity();
return getResponseEntity.getContent();
}
catch (IOException e) {
getRequest.abort();
Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
}
return null;
}
Then in my parse data method
InputStream source = retrieveStream(url);
try {
JsonFactory jfactory = new JsonFactory();
JsonParser jParser = jfactory.createJsonParser(source);
Then I parse data as was shown in the tutorial I linked above
while (jParser.nextToken() != JsonToken.END_OBJECT) {
String fieldname = jParser.getCurrentName();
if ("Name".equals(fieldname)) {
jParser.nextToken();
this.setName(jParser.getText());
}
if ("Number".equals(fieldname)) {
jParser.nextToken();
this.setNumber(jParser.getText());
}
}
The url I am using is a dummy site set up which just has a JSON file on it which I am using to practice Jackson JSON parsing.
Now I know my parse data code is fine, as I in normal Java class, I can parse the data from the website using the code I created, and it works fine.
However if I try to use the code in Android with the code I have just shown, I just get a black screen for some odd reason. I have internet permissions enabled in manifest
Is there something wrong with the http code I have used? If so could someone show me how it should be done? And also why I am getting a black screen, I don't understand why it would show that.
Thanks in advance
Not sure if this is the problem, but your looping construct is unsafe: depending on kind of data you get, it is quite possible that you do not get END_OBJECT as the next token. And at the end of content, nextToken() will return null to indicate end-of-input. So perhaps you get into infinite loop with certain input?
I found the issue, the link was local host which could not be accessed from Emulator. Settings were changed, and can now access link, works perfectly now :D
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 5 years ago.
Improve this question
I would like to send messages in the form of JSON objects to a server and parse the JSON response from the server.
Example of JSON object
{
"post": {
"username": "John Doe",
"message": "test message",
"image": "image url",
"time": "current time"
}
}
I am trying to parse the JSON manually by going attribute by attribute. Is there any library/utility I can use to make this process easier?
I am surprised these have not been mentioned: but instead of using bare-bones rather manual process with json.org's little package, GSon and Jackson are much more convenient to use. So:
GSON
Jackson
So you can actually bind to your own POJOs, not some half-assed tree nodes or Lists and Maps.
(and at least Jackson allows binding to such things too (perhaps GSON as well, not sure), JsonNode, Map, List, if you really want these instead of 'real' objects)
EDIT 19-MAR-2014:
Another new contender is Jackson jr library: it uses same fast Streaming parser/generator as Jackson (jackson-core), but data-binding part is tiny (50kB). Functionality is more limited (no annotations, just regular Java Beans), but performance-wise should be fast, and initialization (first-call) overhead very low as well.
So it just might be good choice, especially for smaller apps.
You can use org.json.JSONObject and org.json.JSONTokener. you don't need any external libraries since these classes come with Android SDK
GSON is easiest to use and the way to go if the data have a definite structure.
Download gson.
Add it to the referenced libraries.
package com.tut.JSON;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class SimpleJson extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String jString = "{\"username\": \"tom\", \"message\": \"roger that\"} ";
GsonBuilder gsonb = new GsonBuilder();
Gson gson = gsonb.create();
Post pst;
try {
pst = gson.fromJson(jString, Post.class);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
Code for Post class
package com.tut.JSON;
public class Post {
String message;
String time;
String username;
Bitmap icon;
}
This is the JsonParser class
public class JSONParser {
static InputStream is = null;
static JSONObject jObj = null;
static String json = "";
// constructor
public JSONParser() {
}
public JSONObject getJSONFromUrl(String url) {
// Making HTTP request
try {
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
json = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
// try parse the string to a JSON object
try {
jObj = new JSONObject(json);
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
// return JSON String
return jObj;
}
Note: DefaultHttpClient is no longer supported by sdk 23, so it is advisable to use target sdk 21 with this code.
There's not really anything to JSON. Curly brackets are for "objects" (associative arrays) and square brackets are for arrays without keys (numerically indexed). As far as working with it in Android, there are ready made classes for that included in the sdk (no download required).
Check out these classes:
http://developer.android.com/reference/org/json/package-summary.html
Other answers have noted Jackson and GSON - the popular add-on JSON libraries for Android, and json.org, the bare-bones JSON package that is included in Android.
But I think it is also worth noting that Android now has its own full featured JSON API.
This was added in Honeycomb: API level 11.
This comprises
- android.util.JsonReader: docs, and source
- android.util.JsonWriter: docs, and source
I will also add one additional consideration that pushes me back towards Jackson and GSON: I have found it useful to use 3rd party libraries rather then android.* packages because then the code I write can be shared between client and server. This is particularly relevant for something like JSON, where you might want to serialize data to JSON on one end for sending to the other end. For use cases like that, if you use Java on both ends it helps to avoid introducing android.* dependencies.
Or I guess one could grab the relevant android.* source code and add it to your server project, but I haven't tried that...
You can download a library from http://json.org (Json-lib or org.json) and use it to parse/generate the JSON
you just need to import this
import org.json.JSONObject;
constructing the String that you want to send
JSONObject param=new JSONObject();
JSONObject post=new JSONObject();
im using two object because you can have an jsonObject within another
post.put("username(here i write the key)","someusername"(here i put the value);
post.put("message","this is a sweet message");
post.put("image","http://localhost/someimage.jpg");
post.put("time": "present time");
then i put the post json inside another like this
param.put("post",post);
this is the method that i use to make a request
makeRequest(param.toString());
public JSONObject makeRequest(String param)
{
try
{
setting the connection
urlConnection = new URL("your url");
connection = (HttpURLConnection) urlConnection.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-type", "application/json;charset=UTF-8");
connection.setReadTimeout(60000);
connection.setConnectTimeout(60000);
connection.connect();
setting the outputstream
dataOutputStream = new DataOutputStream(connection.getOutputStream());
i use this to see in the logcat what i am sending
Log.d("OUTPUT STREAM " ,param);
dataOutputStream.writeBytes(param);
dataOutputStream.flush();
dataOutputStream.close();
InputStream in = new BufferedInputStream(connection.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
result = new StringBuilder();
String line;
here the string is constructed
while ((line = reader.readLine()) != null)
{
result.append(line);
}
i use this log to see what its comming in the response
Log.d("INPUTSTREAM: ",result.toString());
instancing a json with the String that contains the server response
jResponse=new JSONObject(result.toString());
}
catch (IOException e) {
e.printStackTrace();
return jResponse=null;
} catch (JSONException e)
{
e.printStackTrace();
return jResponse=null;
}
connection.disconnect();
return jResponse;
}
if your are looking for fast json parsing in android than i suggest you a tool which is freely available.
JSON Class Creator tool
It's free to use and it's create your all json parsing class within a one-two seconds.. :D
Although there are already excellent answers are provided by users such as encouraging use of GSON etc. I would like to suggest use of org.json. It includes most of GSON functionalities. It also allows you to pass json string as an argument to it's JSONObject and it will take care of rest e.g:
JSONObject json = new JSONObject("some random json string");
This functionality make it my personal favorite.
There are different open source libraries, which you can use for parsing json.
org.json :- If you want to read or write json then you can use this library.
First create JsonObject :-
JSONObject jsonObj = new JSONObject(<jsonStr>);
Now, use this object to get your values :-
String id = jsonObj.getString("id");
You can see complete example here
Jackson databind :- If you want to bind and parse your json to particular POJO class, then you can use jackson-databind library, this will bind your json to POJO class :-
ObjectMapper mapper = new ObjectMapper();
post= mapper.readValue(json, Post.class);
You can see complete example here