RoboServiceTestCase

78 views
Skip to first unread message

Paul Butcher

unread,
Sep 26, 2010, 10:14:06 AM9/26/10
to robo...@googlegroups.com
As you can probably tell from my earlier message, I've been looking at creating a service with RoboGuice. One of the problems that I hit was that I can't test something derived from RoboService using the standard Android ServiceTestCase (it complains about the MockApplication provided by ServiceTestCase). To this end, by using RoboUnitTestCase as an example, I've created an implementation of RoboServiceTestCase (see below), which seems to work in the simple tests I have so far.

I'd be very grateful for your comments on whether this looks right to you - I am just getting started in this area and it's entirely possible that I'm missing something.

This is probably getting ahead of myself, but there's quite a bit of duplication between this and RoboUnitTestCase which should probably be DRYed up before this, or something like it, is integrated into RoboGuice:

Start of code--------------------------------------
package roboguice.test;

import roboguice.application.RoboApplication;
import roboguice.service.RoboService;
import roboguice.inject.ContextScope;

import android.content.Context;
import android.test.ServiceTestCase;

import com.google.inject.Injector;

import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;

public class RoboServiceTestCase<ServiceType extends RoboService, AppType extends RoboApplication> extends ServiceTestCase<ServiceType> {
protected Injector injector;

public RoboServiceTestCase(Class<ServiceType> serviceClass) {
super(serviceClass);
}

@Override
protected void runTest() throws Throwable {
final Context context = getContext();
final Constructor constructor = applicationType().getConstructor(Context.class);
final RoboApplication app = (RoboApplication)constructor.newInstance(context);
injector = app.getInjector();
final ContextScope scope = injector.getInstance(ContextScope.class);
setApplication(app);

try {
scope.enter(context);
super.runTest();
} finally {
scope.exit(context);
}
}

protected Injector getInjector() {
return injector;
}

protected Class<? extends RoboApplication> applicationType() {
final ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
return (Class<? extends RoboApplication>) parameterizedType.getActualTypeArguments()[1];
}
}
End of code-----------------------------------

--
paul.butcher->msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: pa...@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher

Michael Burton

unread,
Sep 27, 2010, 10:13:32 AM9/27/10
to robo...@googlegroups.com
... and who knew your opportunity would come so quickly?!

This looks about right, the basic idea should be the same between RoboUnit and RoboServiceTestCase.  I guess the only thing I'd suggest is a name change to RoboServiceUnitTestCase (and an accompanying change for the original to RoboActivityUnitTestCase)

If you're game, I suggest you make a clone of the repo here: http://code.google.com/p/roboguice/source/clones

Add your new code (don't forget to both checking locally AND push to the google code servers), and when you feel pretty confident about it let me know and I'll pull your changes over.

Cheers,
Mike


--
You received this message because you are subscribed to the Google Groups "roboguice" group.
To post to this group, send email to robo...@googlegroups.com.
To unsubscribe from this group, send email to roboguice+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/roboguice?hl=en.


Paul Butcher

unread,
Sep 27, 2010, 10:37:06 AM9/27/10
to robo...@googlegroups.com
Great - will do.

I'm absolutely maxed out at the moment (we released our first app - SwiftKey - on the marketplace last week, and things have been crazy ever since), so don't be surprised if you don't see anything for a while, but it doesn't mean that I've forgotten :-)

Thanks!

Paul Butcher

unread,
Sep 28, 2010, 10:54:13 AM9/28/10
to robo...@googlegroups.com
Is there any reason why the setup (creating the application object, getting the injector, etc.) happens in runTest and not in setUp and tearDown? I've just found myself wanting to get access to the injector in my test class' setUp method, and at the moment it's null.

I.e. could RoboUnitTestCase lose its runTest method and instead have:

> Context context;
> ContextScope scope;
>
> @Override
> protected void setUp() throws Exception {
> context = getInstrumentation().getTargetContext();


> final Constructor constructor = applicationType().getConstructor(Context.class);
> final RoboApplication app = (RoboApplication)constructor.newInstance(context);
> injector = app.getInjector();

> scope = injector.getInstance(ContextScope.class);
>
> scope.enter(context);
> }
>
> @Override
> protected void tearDown() throws Exception {
> scope.exit(context);
> }

(or something along those lines)?

Michael Burton

unread,
Sep 28, 2010, 11:16:21 AM9/28/10
to robo...@googlegroups.com
I recall being frustrated when trying to get the guice injection configured during setup.  IIRC there was some limitation in InstrumentationTestCase that prevented that from working properly, but I don't remember the details and could be misremembering.

That being said, the test framework documentation was poor when I wrote that, and looking at it now it appears significantly more robust (eg. http://developer.android.com/intl/fr/guide/topics/testing/testing_android.html ).  It's possible it was done that way simply out of ignorance.

Does moving it to setUp work for you?




Paul Butcher

unread,
Sep 28, 2010, 11:45:24 AM9/28/10
to robo...@googlegroups.com
On 28 Sep 2010, at 16:16, Michael Burton wrote:
> Does moving it to setUp work for you?

Seems to, yup.

I'll add this to the list of things to do when I put my patch together.

Reply all
Reply to author
Forward
0 new messages