Robolectric custom shadow classes not working

935 views
Skip to first unread message

Kanishk Tripathi

unread,
Jun 11, 2015, 10:36:48 AM6/11/15
to robol...@googlegroups.com
I am having problem running shadow classes code in Robolectric. Or maybe my understanding of shadows is wrong. I have created a custom shadow.
This is the class that I am shadowing. Using robolectric-3, Android studio and gradle

public class MyConfig {

public static final String TEST = "test";

public static boolean testMethod() {
return false;
}

public boolean returnVal() { return false;}
}

This is the custom shadow class.

@Implements(value = MyConfig.class, isInAndroidSdk = false)
public class ShadowConfig {

public static final String TEST = "test";

@Implementation
public static boolean testMethod() {
return true;
}
 
    @Implementation
public boolean returnVal() { return true;}
}

The ShadowConfig is in src/test/java folder and MyConfig is in src/main/java folder.

This is my test case.

@RunWith(RobolectricGradleTestRunner.class)
@Config(emulateSdk = 21, constants = BuildConfig.class, shadows = {ShadowConfig.class})
public class MyTest {

@Test
public void myActivityAppearsAsExpectedInitially() {
MyConfig config = new MyConfig();
assertTrue("Test boolean", MyConfig.testMethod());
        assertTrue("Test boolean", config.returnVal());
}
}

If I have shadow implementation added to the test case, then it should run the methods of ShadowConfig instead of MyConfig class. But in this case,
its runnning the code of MyConfig class. Can anyone tell if my understanding is incorrect or I am doing anything wrong.

Mike Grafton

unread,
Jun 12, 2015, 11:01:55 AM6/12/15
to robol...@googlegroups.com
Hi Kanishk,

Indeed, this is not how Shadows are meant to be used.  Shadows are useful for intercepting call to the Android SDK, and Robolectric only instruments core Android classes for shadowing. Since MyConfig is in your code's package, Robolectric will not shadow it.

It is possible to use shadowing for this purpose, but not recommended. There are much more straightforward ways - like using mocks or fake implementations with dependency injection.

Mike

Kanishk Tripathi

unread,
Jun 12, 2015, 12:36:41 PM6/12/15
to robol...@googlegroups.com
Hi Mike, 
Yes, I understood the concept of Shadows. I also found how to shadow classes from my own code's package. The problem is that I have a class in my code base that has static native methods. It loads native libraries from JNI. Also those native methods are called in static block so called after class loading. It also contains lots of constants. So the class object is not created. Only its static members and functions are accessed. Now this class is not directly used in my unit tests. Its called from within the methods which I am testing through my code. Since robolectric does not support any native library loading, it gives an error when running the tests. So far I have found how to shadow this class but a better approach is most welcome.
One approach could be to separate the native libraries call in a single file and then mock them. 
The question is, how can I mock it across my whole test cases?

--
You received this message because you are subscribed to a topic in the Google Groups "Robolectric" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/robolectric/38ym6CU1-wU/unsubscribe.
To unsubscribe from this group and all its topics, send an email to robolectric...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Kanishk Tripathi

Fr Jeremy Krieg

unread,
Jun 12, 2015, 2:15:04 PM6/12/15
to robol...@googlegroups.com
Hi Kanishk,

I think that what Mike said is true by default - ie, it will only shadow Android classes. However, I think you can tell it to shadow other classes too - as long as they are not loaded too early on in the piece it will work (eg, you can't shadow classes in java.lang).

If you can't get that to work, then JMockit will be able to mock out the static library loader for you. You will want to use a MockUp subclass instead of a Shadow.

Hope that helps.

-Fr Jeremy

Jonathan Gerrish

unread,
Jun 14, 2015, 12:20:37 PM6/14/15
to robol...@googlegroups.com
Hi Kanishk,

I would follow one of your own suggestions:- separate out the native library loading code from the rest of that class. If you are just referencing constants in it in the class under test you may not want to automatically incur the cost of the native library code anyway. For testing code that calls the native methods, then inject a mock instead.

Jonathan

--
You received this message because you are subscribed to the Google Groups "Robolectric" group.
To unsubscribe from this group and stop receiving emails from it, send an email to robolectric...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages