Testing method with Context as parameter

3,090 views
Skip to first unread message

Macarse

unread,
Nov 18, 2010, 10:08:59 AM11/18/10
to robolectric
Yesterday I made a blog post about TDD in android [1].
Phil Goodwin passed by and recommend me Robolectric, so here I am :).

I have been looking into it and watching this presentation:
http://www.slideshare.net/tylerschultz/robolectric-android-unit-testing-framework

The first thing I try to test with Robolectric is the following class:

public class CarService extends JsonService {

public static List<Car> getCars(Context context) {

String carsJson = readJson(context, R.raw.cars);
Type type = new TypeToken<List<Car>>() {
}.getType();
List<Car> retrievedCars = new Gson().fromJson(carsJson,
type);

return retrievedCars;
}
}


JsonService:

public class JsonService {

protected static String readJson(Context context, int id) {
InputStream inputStream =
context.getResources().openRawResource(id);
ByteArrayOutputStream byteArrayOutputStream = new
ByteArrayOutputStream();

int i;
try {
i = inputStream.read();
while (i != -1) {
byteArrayOutputStream.write(i);
i = inputStream.read();
}
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}

return byteArrayOutputStream.toString();
}
}


What should I do here?
Is there a way to use the context inside test?
Should I add the json file as a test resource?
Should I modify my class to get as a paramater a json instead of
Context?

What would you recommend?

Thanks

PS: http://pivotal.github.com/robolectric/ should have a link to the
group instead of a mailto.

[1] http://t.co/IjSwsSi

Tyler Schultz

unread,
Nov 18, 2010, 12:59:58 PM11/18/10
to robol...@googlegroups.com
Macarse,

Awesome!  Good to see you're giving Robolectric a shot!

If the code you're writing has a dependency on a context you can simply new one up.  Robolectric is makes this possible:

@Test
public void carServiceShouldParseJson() {
Context context = new Context();
CarService carService = new CarService(context, R.string.car_json);
List<Cars> cars = carService.getCars(

assertThat(cars.size(), equalTo(10));
}

This is ultimately the test you'd probably like to write, but there's something more to do and understand.

I assume you have a basic understanding of Robolectric and shadow objects.  

The context object will have a shadow context backing it, giving the context behavior. The method you're invoking on the context is getResources().  This will return a Resources object that has a backing ShadowResources object.  ShadowResources implements many of the methods on Resources, but you happen to be using a method that does not have an implementation, yet. You're using Resources#getRawResource(int id) and ShadowResources does not have an implementation for it.  This means that the method will return null.

So... now what?  There's a few things you can do:  

1.  Stop using the jar file and fork the Robolectric repo and include it in your project.  This will allow you to modify the ShadowResources object and add your implementation of getRawResources(int id), and as a plus, you can submit a pull request back to Robolectric so the rest of the world can make use of your implementation.

2. Use a different method on Resources that has a ShadowResources implementation.  

3. Restructure your code so that you're separating the loading of the JSON from the parsing of the JSON, so that you can test these behaviors independently.  


--Tyler

Joseph Moore

unread,
Nov 19, 2010, 9:15:57 AM11/19/10
to robol...@googlegroups.com
This reply would be an excellent blog post somewhere, perhaps on the Pivotal Blabs or on a robolectric-specific blog?

Macarse

unread,
Nov 19, 2010, 9:20:28 AM11/19/10
to robol...@googlegroups.com
I just forked the project and I am trying to add the getRaw() method
but one of the tests fails:
https://github.com/pivotal/robolectric/issues/issue/4

Phil

unread,
Nov 19, 2010, 1:45:45 PM11/19/10
to robolectric
On Nov 19, 6:20 am, Macarse <maca...@gmail.com> wrote:
> I just forked the project and I am trying to add the getRaw() method
> but one of the tests fails:https://github.com/pivotal/robolectric/issues/issue/4

Thanks for reporting this. It's been fixed on head.

Christian Williams

unread,
Nov 19, 2010, 5:47:06 PM11/19/10
to robol...@googlegroups.com
Phil just released robolectric 0.9.1, which fixes this issue. Thanks for the bug report!

--X

Macarse

unread,
Nov 21, 2010, 8:18:44 PM11/21/10
to robol...@googlegroups.com
Np.

I am willing to do the code to support raw resources but I have some questions.
Should I create the issue and continue the discussion there or it's ok
to have it right here in the mailing list?

Thanks.

Christian Williams

unread,
Nov 21, 2010, 9:10:22 PM11/21/10
to robol...@googlegroups.com
Right here is cool!

--X [typos courtesy of my iPhone]

Lilibeth

unread,
Nov 23, 2010, 9:07:18 AM11/23/10
to robolectric
Hey,

I'm having a similar problem, but this code won't even compile for me.
Context is an abstract class and cannot be instantiated. Is there
something else that needs to be done, included, etc. ?

On Nov 18, 1:59 pm, Tyler Schultz <tylerschu...@gmail.com> wrote:
> Macarse,
>
> Awesome!  Good to see you're giving Robolectric a shot!
>
> If the code you're writing has a dependency on a context you can simply new
> one up.  Robolectric is makes this possible:
>
> @Test
> public void carServiceShouldParseJson() {
>
> Context context = new Context();
> CarService carService = new CarService(context, R.string.car_json);
> List<Cars> cars = carService.getCars(
>
> assertThat(cars.size(), equalTo(10));
>
> }
>
> This is ultimately the test you'd probably like to write, but there's
> something more to do and understand.
>
> I assume you have a basic understanding of Robolectric and shadow objects.
>
> The context object will have a shadow context backing it, giving the context
> behavior. The method you're invoking on the context is getResources().  This
> will return a Resources object that has a backing ShadowResources object.
>  ShadowResources implements many of the methods on Resources, but you happen
> to be using a method that does not have an implementation, *yet. *You're
> using Resources#getRawResource(int id) and ShadowResources does not have an
> implementation for it.  This means that the method will return null.
>
> So... now what?  There's a few things you can do:
>
> 1.  Stop using the jar file and fork the Robolectric repo and include it in
> your project.  This will allow you to modify the ShadowResources object and
> add your implementation of getRawResources(int id), and as a plus, you can
> submit a pull request back to Robolectric so the rest of the world can make
> use of your implementation.
>
> 2. Use a different method on Resources that has a ShadowResources
> implementation.
>
> 3. Restructure your code so that you're separating the loading of the JSON
> from the parsing of the JSON, so that you can test these behaviors
> independently.
>
> --Tyler
>
> On Thu, Nov 18, 2010 at 7:08 AM, Macarse <maca...@gmail.com> wrote:
> > Yesterday I made a blog post about TDD in android [1].
> > Phil Goodwin passed by and recommend me Robolectric, so here I am :).
>
> > I have been looking into it and watching this presentation:
>
> >http://www.slideshare.net/tylerschultz/robolectric-android-unit-testi...
> > PS:http://pivotal.github.com/robolectric/should have a link to the

Tyler Schultz

unread,
Nov 23, 2010, 10:30:51 AM11/23/10
to robol...@googlegroups.com
You're totally I'm sorry, you'll have to forgive me, I gave a bad example.

Instead of using a context, you can use a ContextWrapper, or an Activity, or any other class that derives from Context.

The code should have read:

@Test
public void carServiceShouldParseJson() {
Context context = new Activity();

assertThat(cars.size(), equalTo(10));
}

Tyler Schultz

unread,
Nov 23, 2010, 10:43:49 AM11/23/10
to robol...@googlegroups.com
Lilibeth,

There are also lots of examples inside of the RobolectricSample project found here:


--Tyler

Macarse

unread,
Nov 23, 2010, 11:04:25 AM11/23/10
to robol...@googlegroups.com
I just updated my branch and I am still failing that test case I mentioned.
https://github.com/pivotal/robolectric/issues/closed#issue/4

Am I missing something?

Thanks

Macarse

unread,
Nov 23, 2010, 2:09:27 PM11/23/10
to robol...@googlegroups.com
Ok, just added the res/raw support.
I created the issue and mention I fix it in the commit offered as pull request.

Let me know what you think.

Thanks.

Christian Williams

unread,
Nov 23, 2010, 4:12:00 PM11/23/10
to robol...@googlegroups.com
Did you pull down robolectric 0.9.1?

--X

Macarse

unread,
Nov 23, 2010, 4:13:10 PM11/23/10
to robol...@googlegroups.com
I just merged my branch with master.

Christian Williams

unread,
Nov 23, 2010, 4:18:44 PM11/23/10
to robol...@googlegroups.com
Make sure you've added the json-xxxxxxxx.jar to your classpath.

--X

Macarse

unread,
Nov 24, 2010, 6:47:04 AM11/24/10
to robol...@googlegroups.com
Yep. I have json-20090211.jar
Does it work for you?

On Tue, Nov 23, 2010 at 6:18 PM, Christian Williams

Christian Williams

unread,
Nov 24, 2010, 2:49:34 PM11/24/10
to robol...@googlegroups.com
You're still getting this error right?

java.lang.RuntimeException: Stub!
at org.json.JSONObject.<init>(JSONObject.java:8)

The json.jar needs to be *before* android.jar in the classpath, otherwise you'll get the stubbed classes from android.jar. Maybe that's the problem?

--X

Macarse

unread,
Nov 25, 2010, 6:38:41 AM11/25/10
to robol...@googlegroups.com
Oh. That worked.
I just reordered the maven deps and it worked.

now I should learn why:

initializationError(com.xtremelabs.robolectric.util.TestUtil)

is failing.

Thanks Christian!

On Wed, Nov 24, 2010 at 4:49 PM, Christian Williams

Reply all
Reply to author
Forward
Message has been deleted
0 new messages