unit testing - Android java.lang.NoClassDefFoundError: R$string -
whenever run unit test, error when tries retrieve string value custom config.xml file.
background:
the project library apk project uses , references library apk project.
the error occurs when project tries initiate new object subclass of super class contained on referenced library apk project.
the issue explained more below
the specific line of code fails error static variable defined below:
protected static final string android_config_id = libraryapplication.getapplication().getstring(r.string.api_checkout_config_id_override);
it fails following error:
java.lang.noclassdeffounderror: com/jon/commonlib/r$string
commonlib referenced library apk if wondering.
here unit test
@runwith(robolectrictestrunner.class) @config(constants = buildconfig.class, manifest=config.none) public class testsearchshows { @test public void testsearchjsonfile(){ eventstesthelper testhelper = new eventstesthelper(runtimeenvironment.application); try { showslist showlist = testhelper.getshowlist(new searchevent()); if(showlist.getshows().size() < 0){ assert.fail("show list empty"); } } catch (ioexception e) { e.printstacktrace(); assert.fail(e.tostring()); } } }
the eventstesthelper sub class super class called networkhelper looks this:
public abstract class networkhelper<t, p, s> implements networkconstants { protected static final string android_config_id = libraryapplication.getapplication().getstring(r.string.api_checkout_config_id_override); //other stuff .... }
i use robolectric version 3.0 latest runing ,my unit tests.
if run code live , call , initiate sub class, works fine, no crashes
edit: here snippets of build gradle file below
apply plugin: 'android-sdk-manager' apply plugin: 'com.android.library' apply plugin: 'crashlytics' buildscript { repositories { jcenter() mavencentral() maven { url 'http://download.crashlytics.com/maven' } maven { url 'http://www.testfairy.com/maven' } } dependencies { classpath 'com.android.tools.build:gradle:1.1.0' classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.+' classpath 'com.crashlytics.tools.gradle:crashlytics-gradle:1.+' classpath 'com.testfairy.plugins.gradle:testfairy:1.+' } } repositories { mavencentral() maven { url 'http://download.crashlytics.com/maven' } maven { url "https://oss.sonatype.org/content/repositories/snapshots" } flatdir { dirs 'libs' } } android { compilesdkversion 19 buildtoolsversion "22.0.1" def package_namespace = "com.jonney.moduleapp" defaultconfig { minsdkversion 14 testapplicationid "com.jonney.moduleapp" targetsdkversion 19 versioncode 1 versionname "1.0" } productflavors { //testing { //} local { } mock { } qa { } //qa4 { //} production { } } sourcesets { local { res.srcdir 'build-config/local/res' } testing { res.srcdir 'build-config/testing/res' } mock { res.srcdir 'build-config/mock/res' } qa { res.srcdir 'build-config/qa/res' } qa4 { res.srcdir 'build-config/qa4/res' } staging { res.srcdir 'build-config/staging/res' test.java.srcdirs += 'src/main/java' } production { res.srcdir 'build-config/production/res' test.java.srcdirs += 'src/main/java' test.java.srcdirs += "build/generated/source/r/production" test.java.srcdirs += "build/generated/source/buildconfig/production" } } } dependencies { compile filetree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:19.1.+' compile 'com.google.code.gson:gson:2.3' testcompile('org.robolectric:robolectric:3.0') { exclude group: 'commons-logging', module: 'commons-logging' exclude group: 'org.apache.httpcomponents', module: 'httpclient' } compile 'com.fasterxml.jackson:jackson-parent:2.5' compile 'com.squareup:otto:1.3.6' compile 'com.jakewharton:butterknife:6.1.0' compile 'com.sothree.slidinguppanel:library:3.0.0' compile 'com.crashlytics.android:crashlytics:1.+' compile 'com.mcxiaoke.volley:library-aar:1.0.0' compile "joda-time:joda-time:2.4" testcompile('junit:junit:4.12') { exclude module: 'hamcrest' exclude module: 'hamcrest-core' } testcompile 'org.hamcrest:hamcrest-all:1.3' compile 'com.sothree.slidinguppanel:library:3.0.0' compile 'com.squareup:otto:1.3.6' compile 'com.squareup.okhttp:okhttp:2.3.0' testcompile 'org.apache.maven:maven-ant-tasks:2.1.3' compile 'com.google.android.gms:play-services:7.0.0' compile 'com.android.support:multidex:1.0.0' compile(name: 'commonlib 1.0 1', ext: 'aar') testcompile(name: 'commonlib-1.0 1', ext: 'aar') }
edit: have tried manually create task copies r class each dependency.
afterevaluate { project -> android.libraryvariants.each { variant -> // workaround missing r class aar dependencies def copytaskname = "copy${variant.name.capitalize()}appcompat" def copytasknametwo = "copy${variant.name.capitalize()}commonlib" task(copytaskname, type:copy) { dependson "process${variant.name.capitalize()}resources" { "build/generated/source/r/${variant.dirname}/$package_namespace_path" } { "build/generated/source/r/${variant.dirname}/com/jon/commonlib" } // { "src/test/java/android/support/v7/appcompat" } include 'r.java' filter { line -> line.contains("package ${package_namespace};") ? 'package android.support.v7.appcompat;' : line } outputs.uptodatewhen { false } } task(copytasknametwo, type:copy) { dependson "process${variant.name.capitalize()}resources" { "build/generated/source/r/${variant.dirname}/$package_namespace_path" } { "build/generated/source/r/${variant.dirname}/android/support/v7/appcompat" } // { "src/test/java/android/support/v7/appcompat" } include 'r.java' filter { line -> line.contains("package ${package_namespace};") ? 'package com.jon.commonlib;' : line } outputs.uptodatewhen { false } } system.out.println("adding ${copytaskname} build/generated/source/r/${variant.dirname}/$package_namespace_path ") println("basename = ${variant.basename}") println("directory name = ${variant.dirname}") tasks.getbyname("compile${variant.name.capitalize()}unittestjava") dependson copytaskname } }
kind regards
jonnney
the project library apk project uses , references library apk project.
for type of projects exist known issue https://github.com/robolectric/robolectric/issues/1796 can workaround it.
the base issue android/gradle behaviour library projects different compared application projects. ignores generate r classes aar dependencies.
to workaround can provide own r class contains dependencies r values. here example appcompat dependency
afterevaluate { project -> android.libraryvariants.each { variant -> // 1 line each aar dependency tasks.getbyname("assemble${variant.name.capitalize()}").dependson copyappcompat } } // copy each aar dependency , adjust needs task copyappcompat(type: copy) { // replace base package yours (all after /r/debug/) contains r.class 'build/generated/source/r/debug/com/example/core'.replace("/", file.separator) // replace library packages yours (all after /test/java/) aar dependency base package 'src/test/java/android/support/v7/appcompat'.replace("/", file.separator) // replace package declaration or compile errors filter { line -> line.contains('package com.example.core;') ? 'package android.support.v7.appcompat;' : line } include 'r.java' }
an example project setup can found @ https://github.com/nenick/androidstudioandrobolectric/tree/library-with-aar
Comments
Post a Comment