Robolectric - Could not load class: org.robolectric.shadows.ShadowMultiDex - android

I am configuring Robolectric for a project that uses multi dex. I am using Robolectric 3.0 RC3 which should support Multidex without throwing that "Multi dex installation failed" exception.
testCompile('org.robolectric:robolectric:3.0-rc3')
My sample test is in src/test/java/SandwichTest:
#RunWith(RobolectricGradleTestRunner.class)
public class SandwichTest {
#Test
public void firstTest() { }
}
I have a global configuration file to load ShadowMultiDex in src/test/resources called robolectric.properties per the instructions on the Robolectric site:
shadows=org.robolectric.shadows.ShadowMultiDex
When I run my sample SandwichTest, I get this exception:
Could not load class: org.robolectric.shadows.ShadowMultiDex
java.lang.RuntimeException: Could not load class: org.robolectric.shadows.ShadowMultiDex
at org.robolectric.annotation.Config$Implementation.parseClass(Config.java:147)
It looks like Robolectric is finding my configuration file but is unable to load the ShadowMultiDex class. Attempting to add the shadow multi dex module to my gradle file manually:
testCompile('org.robolectric:shadows-multidex:3.0-SNAPSHOT')
or
testCompile('org.robolectric:shadows-multidex')
Causes "failed to resolve" issues during sync.
What steps am I missing to get this sample test to run?

In your question, I noticed you were missing a version on your Gradle dependency.
You have:
testCompile('org.robolectric:shadows-multidex')
You need:
testCompile('org.robolectric:shadows-multidex:3.0')
Actual Release: https://oss.sonatype.org/content/repositories/releases/org/robolectric/shadows-multidex/
You should remove the:
shadows=org.robolectric.shadows.ShadowMultiDex
from your src/test/resources/robolectric.properties file. That is used for custom Shadows.

Related

Testing inconvenience: Android Studio JUnit vs Gradle based: testOptions ignored by Android Studio

The following was done with Android Studio 3.4, Android Gradle Plugin 3.3.2 and Gradle 4.10.3.
In the build.gradle file, I have configured some unit test options like this:
android {
testOptions {
unitTests.all {
systemProperty "debug","true"
}
}
}
I do have a test function that tries to read this property:
package com.demo;
public class SysPropTestDemo {
#Test
public static void dumpSysProps() {
System.out.println("sysprop(debug)=" + System.getProperty("debug"));
}
}
When run via command line gradlew test --test com.demo.SysPropTestDemo I will get the property debug set correctly to true. If I run the same test via Android Studio without setting any options, the value shown will be null.
In order to get the same result from Android Studio, I explicitly have to enter some values in the "Run/Debug Configurations" panel, i.e something like -Ddebug=true in the VM options.
Now this is a trivial example, but what I really want to do, is to add some path to the java.library.path property in order to be able to load a JNI library compiled within the project. (I do need to write some tests that make use a modified SQLite lib, so not using JNI is not an option here)
It does work when setting additional options, but I think this is very inconvenient, since I can't enter a variable based value in the configuration options (or at least, I don't know how to). To sum it up: when setting or changing values, I do have to go through a bunch of config screens where I would really prefer to have one place in a config file.
Shouldn't Android Studio somehow make use of the values specified in the build.gradle file? If not, the docs don't make it clear that the testOptions.unitTests.all settings can only be used via gradlew invocation.
Skybow,
I feel you have two questions
1. How to load jni lib for androidTest(not for 'test[non instrumented unit tests])
- copy your jni library in corresponding folder [JNI libraries: [app/src/androidTestFLAVORNAMEDebug/jniLibs]
- load your jni library
static {
try {
System.loadLibrary("xyzjni");
} catch (Exception e) {
Logger.error("Exception on loading the jni library : " + e.getMessage());
}
}
2. How to make android studio use your config variables defined for unitTests.
- It would have great if some text file is there which has all configs.
- Or it is part of build.gradle
- I don't have any detail on this.

Scala reflection java.rmi dependency, can it work on Android?

I would like to use the Scala (2.11) reflection package's runtime mirror in a Scala application compiled for android which is being build using Scala on android.
I was able to fiddle with ProGuard options in order to make it include the required Scala classes. However when I try to get a mirror instance:
universe.runtimeMirror(this.getClass.getClassLoader)
(Indeed it fails during the lazy computation of universe)
The application crashes in run time:
java.lang.NoClassDefFoundError: Failed resolution of: Ljava/rmi/Remote;
at scala.reflect.internal.Definitions$DefinitionsClass.RemoteInterfaceClass$lzycompute(Definitions.scala:370)
at scala.reflect.internal.Definitions$DefinitionsClass.RemoteInterfaceClass(D efinitions.scala:370)
at scala.reflect.runtime.JavaUniverseForce$class.force(JavaUniverseForce.scal a:255)
at scala.reflect.runtime.JavaUniverse.force(JavaUniverse.scala:16)
at scala.reflect.runtime.JavaUniverse.init(JavaUniverse.scala:147)
at scala.reflect.runtime.JavaUniverse.<init>(JavaUniverse.scala:78)
at scala.reflect.runtime.package$.universe$lzycompute(package.scala:17)
at scala.reflect.runtime.package$.universe(package.scala:17)
This crash is for me as expected as it isn't:
It is expected as java.rmi is not part of the Android API and I should expect any code trying to load its classes to crash.
It is unexpected as I didn't know that Scala's reflect package used java.rmi
I have traced the code to were rmi is required, that is to JavaUniverse (a trait mixed in JavaUniverse class) force method:
...
definitions.RemoteInterfaceClass
...
Which leads to DefinitionsClass:
lazy val RemoteInterfaceClass = requiredClass[java.rmi.Remote]
Am I wrong to think that this is a no-go for Scala reflection in Android?
If I am, what could be a workaround to this problem?
To summarize your solution and a related solution, it is sufficient to add two files, and modify build.sbt to include:
dexAdditionalParams in Android += "--core-library"
Add java/rmi/Remote.java to your project with the content:
package java.rmi;
public interface Remote {}
Add java/rmi/RemoteException.java to your project with the content:
package java.rmi;
public interface RemoteException {}

VerifyError using Mockito 1.9.5 and DexMaker-Mockito-1.0

Like many others I was excited to hear that Mockito now works with Android and followed this tutorial to see it with my own eyes. Everything seemed fan-flapping-tastic and I got underway incorporating the mocking solution into my Android Test Project...
The error
However, on setting up my application's test project to leverage the mockito-all-1.9.5, dexmaker-1.0 and dexmaker-mockito-1.0 jars I encountered a problem with my very first test case. Precisely this problem in fact. The part that I would like assistance on is;
Caused by: java.lang.VerifyError: org/mockito/cglib/core/ReflectUtils
at org.mockito.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:167)
at org.mockito.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:217)
at org.mockito.cglib.core.KeyFactory$Generator.create(KeyFactory.java:145)
at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:117)
at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:109)
at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:105)
at org.mockito.cglib.proxy.Enhancer.<clinit>(Enhancer.java:70)
I have been informed that this "simply doesn't quite work yet" since the stack trace implies that the DexMaker jar is not being used - reference this response. However, I am suspicious that I am doing something wrong with respect to my project set-up so I'm looking to draw from the collective knowledge base here to see if indeed this is user error or a beta-bug.
My Android Test Project set-up
Please find below a screenshot of my test project's configuration. The project was created via the Android Wizard and shares no special features other than the inclusion of the Mockito and DexMaker jars (mentioned above) under the libs directory.
The Test
Never mind the content of the test (the test fails before the unit test is executed) the set-up is as described below;
public class TestSpotRatingCalculator extends InstrumentationTestCase {
#Mock
private AService aService; // Changed the service names being used here - not important.
#Mock
private BService bService;
#Mock
private CService cService;
#Mock
private DService dService;
/**
* #see android.test.AndroidTestCase#setUp()
*/
#Override
protected void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this); // Failure here with aforementioned stacktrace...
}
If anyone out there has an idea what is wrong then please sound-off here.
Hi I had the same problem and I found this article really usefull!
http://corner.squareup.com/2012/10/mockito-android.html
The key piece of information is:
To use Mockito on a device or emulator, you’ll need to add three .jar
files to your test project’s libs directory: mockito-all-1.9.5.jar,
dexmaker-1.0.jar, and dexmaker-mockito-1.0.jar.
Just add this in your gradle:
androidTestCompile 'org.mockito:mockito-core:1.10.8'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.1'
We just had the same problem in a project, but our tests also failed on a real device.
The cause was tracked to how Mockito uses the class loader, and resulted in the following error in LogCat:
W/ActivityThread(5777): ClassLoader.getResources: The class loader returned by Thread.getContextClassLoader() may fail for processes that host multiple applications. You should explicitly specify a context class loader. For example: Thread.setContextClassLoader(getClass().getClassLoader());
The fix was to explicitly set the class loader before calling mock() a test, eg.
#Override
protected void setUp() throws Exception {
super.setUp();
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
fooImpl = mock(Foo.class)
}
The problematic file in Mockito is this one: org.mockito.internal.configuration.ClassPathLoader (line 121 in 1.9.5)
As hinted at here the dexmaker-android combo only works 100% when the instrumented tests are run against a real device.
Running the tests against a real device do not exhibit this failure.
For everybody who still have this error, check if you didn't exclude a class in the dependecies. We exluded by accident the MockMaker.class so this was then the cause for the exception.

Robolectric HTTP test fails on NoSuchMethodError: org.apache.http.impl.client.DefaultRequestDirector

I'm trying to test HTTP calls using the Robolectric test framework's HTTP layer.
My test class is already annotated with RunWith(RobolectricTestRunner.class). Here's a sample HTTP test case:
#Test
public void testHttpGet() {
Robolectric.addPendingHttpResponse(200, "All your requests are belong to Robolectric");
String response = ConnectionUtils.sendRequest();
assertThat(response, equalTo("All your requests are belong to Robolectric"));
}
This test fails and the JUnit Failure Trace reports the following DefaultRequestDirector exception (originating from the sendRequest() call):
java.lang.NoSuchMethodError: org.apache.http.impl.client.DefaultRequestDirector.<init>(Lorg/apache/commons/logging/Log;Lorg/apache/http/protocol/HttpRequestExecutor;Lorg/apache/http/conn/ClientConnectionManager;Lorg/apache/http/ConnectionReuseStrategy;Lorg/apache/http/conn/ConnectionKeepAliveStrategy;Lorg/apache/http/conn/routing/HttpRoutePlanner;Lorg/apache/http/protocol/HttpProcessor;Lorg/apache/http/client/HttpRequestRetryHandler;Lorg/apache/http/client/RedirectHandler;Lorg/apache/http/client/AuthenticationHandler;Lorg/apache/http/client/AuthenticationHandler;Lorg/apache/http/client/UserTokenHandler;Lorg/apache/http/params/HttpParams;)V
at org.apache.http.impl.client.AbstractHttpClient.createClientRequestDirector(AbstractHttpClient.java:660)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:625)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:554)
Any ideas what might be causing the Apache class to throw an exception?
Using the current latest library, robolectric-1.2-20120730.165026-113-jar-with-dependencies.jar.
Found the answer on the Robolectric Google Group: https://groups.google.com/forum/#!msg/robolectric/jWwWjQ23wHI/X9b_ZdDMJg0J
Right click the Robolectric Java test project > Properties > Java Build Path > Order and Export.
Move the robolectric jar to the top of the list of libraries.
Find and remove cached-robolectric-classes.jar. If you followed Robolectric's installation instructions for Eclipse, this file will be under [your main Android project]/tmp.
Rerun JUnit and get back to work.

Monodroid issue with jar binding zubhium sdk

Iam trying to bind a jar(zubhium sdk jar) file to my mono droid project. I have followed their guide on xamarins website and created a new binding project which I reference I my mono droid project.
I am having some issues with package names. I get the following error:
Error 3 package com.zubhium.interfaces does not exist
com.zubhium.interfaces.ZubhiumListener
C:\Users\jbp\Desktop\ny\CmsApp.Droid\obj\Debug\android\src\mono\com\zubhium\interfaces\ZubhiumListenerImplementor.java 8 25 CmsApp.Droid
from the genrated source:
package mono.com.zubhium.interfaces;
public class ZubhiumListenerImplementor
extends java.lang.Object
implements
mono.android.IGCUserPeer,
com.zubhium.interfaces.ZubhiumListener
And that is because when the project is wrapped it automaticly adds mono(.com.zubhium....) to the package name. I cant find how to remove this mono or if i can set a rule to add this part.
I tried to put <attr path="/api/package[#name='com.zubhium.interfaces']" name="managedName">mono.com.zubhium.interfaces</attr>
in the xmldata.xml file but that did not work.
Do you guys have any sugestions?
Regards
package com.zubhium.interfaces does not exist
When you bind a .jar library and reference the binding project from another project, you need to also add the .jar to your Application project and set its Build action to AndroidJavaLibrary.
Failure to do so means that the .jar won't be added to the javac $CLASSPATH, resulting in javac compilation errors when compiling the Android Callable Wrapper (as you saw), and that the .jar won't included into your final .apk. Both of these are Bad™.
And that is because when the project is wrapped it automaticly adds mono(.com.zubhium....) to the package name.
That's for an "Implementor" type; you can ignore it. It's used as part of the implementation of events. If you look at the generated C# code, there should be:
[global::Android.Runtime.Register ("mono/com/zubhium/interfaces/ZubhiumListenerImplementor")]
internal sealed class ZubhiumListenerImplementor : Java.Lang.Object, IZubhiumListener {
// ...
}
The mono.com.zubhium.interfaces.ZubhiumListenerImplementor is the ACW for the internal ZubhiumListenerImplementor type.
You can't rename this type; it's an internal construct that isn't controlled via metadata.

Categories

Resources