How to run POJO test in Android Studio with test bindings? - android

With IntelliJ, I could create a directory "test", add some POJO test files and run them through the IDE.
With Android Studio, I can't find a way to do that. I tried to modify the build.gradle, but I always get the class not found exception.
The next step would be to set up a rule that loads some Guice bindings only during test.
My project looks like:
Project
Module
LibraryModule
src
main
java/com/temp/...
test
java/com/temp/TestClass.java
TestClass.java:
package com.temp;
import org.junit.Before;
import org.junit.Test;
public class TestClass {
#Before
public void setup() throws Exception {
}
#Test
public void testSomething() {
//do something
}
}
build.gradle:
sourceSets {
unitTest {
java.srcDir file('src/test/java')
resources.srcDir file('src/test/resources')
}
}
dependencies {
instrumentTestCompile fileTree(dir: 'libs/test', include: '*.jar')
compile fileTree(dir: 'libs', include: '*.jar')
compile 'com.android.support:support-v4:13.0.0'
}
Error I get:
Class not found: "com.temp.TestClass"
When I run the same project in IntelliJ, I don't get any error. Any tips would help, thanks!

Complete answer (based on what I found here: http://tryge.com/2013/02/28/android-gradle-build/)
build.gradle:
sourceSets {
unitTest {
java.srcDir file('src/test/java')
resources.srcDir file('src/test/resources')
}
}
configurations {
unitTestCompile.extendsFrom runtime
unitTestRuntime.extendsFrom unitTestCompile
}
dependencies {
unitTestCompile files("$project.buildDir/classes/release")
}
task unitTest(type: Test, dependsOn: assemble) {
description = "run unit tests"
testClassesDir = project.sourceSets.unitTest.output.classesDir
classpath = project.sourceSets.unitTest.runtimeClasspath
}
check.dependsOn unitTest
dependencies {
unitTestCompile fileTree(dir: 'libs/test', include: '*.jar')
unitTestCompile fileTree(dir: 'libs', include: '*.jar') // redundant, but don't know how to fix it
compile fileTree(dir: 'libs', include: '*.jar')
compile 'com.android.support:support-v4:13.0.0'
}
Then, to add the test bindings for Guice, make your test class extends that:
public class PojoTestCase {
public PojoTestCase() {
Guice.createInjector(new TestBindings()).injectMembers(this);
}
}
And the way to run:
./gradlew unitTest
Also, the test won't run from Android Studio, but I'm fine with that for now.

Related

android cannot find symbol class RequiresApi after removing ACRA

I need to remove ACRA for removing any vulnerabilities.
I had removed all imports/compiles in app.gradle and MyApplication.java. However, when I tried to build the project, the IDE gives below error:
error: cannot find symbol class RequiresApi
These are my app.gradle and MyApplication.java
app.gradle (I could not build after I removed compile 'ch.acra:acra:4.9.2' in dependencies)
buildscript {
(omitted)
}
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion '27.0.3'
defaultConfig {
applicationId "******"
minSdkVersion 17
targetSdkVersion 22
versionCode 6
versionName "1.0.3"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
disable 'RestrictedApi'
}
}
dependencies {
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:22.2.1'
compile 'com.android.support:design:22.2.1'
compile 'com.android.support:recyclerview-v7:22.2.1'
compile 'com.journeyapps:zxing-android-embedded:3.0.1#aar'
compile 'com.google.zxing:core:3.2.0'
compile 'com.jakewharton:butterknife:8.0.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.0.1'
compile 'net.zetetic:android-database-sqlcipher:3.5.7#aar'
compile 'com.google.code.gson:gson:2.8.2'
//compile 'ch.acra:acra:4.9.2' <- REMOVED ACRA
compile "io.reactivex.rxjava2:rxjava:2.1.9"
compile "io.reactivex.rxjava2:rxandroid:2.0.2"
}
MyApplication.java
package ******;
import android.app.Application;
public class MyApplication extends Application {
private static MyApplication myApplication;
public static MyApplication getInstance() {
return myApplication;
}
public void onCreate() {
super.onCreate();
myApplication = this;
}
}
I had also tried cleaning my project and rebuild, but did not work. When I put ACRA back, the project builds as usual. Is it the problem of IDE?
#RequiresApi is part of com.android.support:support-annotations. You have to add that as a dependency
e.g.
dependencies {
com.android.support:support-annotations:27.1.1
}

Junit Test report (XML/HTML) not generated in android studio

public class StringUtilsTests extends TestCase {
String message;
#Override
protected void setUp() throws Exception {
super.setUp();
message = "33,333";
}
/**
*
*/
public void testCommaToSpaces() {
String result = StringUtils.commasToSpaces(message);
assertEquals("33 333", result);
}
}
build.gradle :-
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:23.0.0'
compile 'com.google.android.gms:play-services-plus:7.5.0'
compile 'com.google.android.gms:play-services-ads:7.5.0'
compile 'com.google.android.gms:play-services-maps:7.5.0'
compile 'com.google.android.gms:play-services-gcm:7.5.0'
compile 'com.google.android.gms:play-services-location:7.5.0'
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.google.code.gson:gson:2.3.1'
// Unit testing dependencies
testCompile 'junit:junit:4.12'
// Set this dependency if you want to use Mockito
testCompile 'org.mockito:mockito-core:1.10.19'
}
testOptions {
unitTests.all {
// All the usual Gradle options.
jvmArgs '-XX:MaxPermSize=256m'
}
}
sourceSets {
unitTest {
java.srcDir file('src/androidTest/java')
}
}
configurations {
unitTestCompile.extendsFrom runtime
unitTestRuntime.extendsFrom unitTestCompile
}
dependencies {
unitTestCompile files("$project.buildDir/results-tests")
}
task unitTest(type: Test, dependsOn: assemble) {
description = "run unit tests"
testClassesDir = project.sourceSets.unitTest.output.classesDir
classpath = project.sourceSets.unitTest.runtimeClasspath
}
check.dependsOn unitTest
I tried lot of things after googling more than a day, but test reports - xml/html are not getting generated. Please kindly guide if anyone has any idea on this.
If i add below line then gradle sync failed.
reports.html.enabled = true
Did you add the line below in your gradle script?
buildTypes {
debug {testCoverageEnabled = TEST_COVERAGE}}
There is an export results option in the test runner. Once the tests have been executed, you can export these results as .html or .xml
It's the right most option.
Click here to see where it is

Android java.lang.NoClassDefFoundError: R$string

whenever i run a unit test, i get this error when it tries to retrieve a string value from a custom config.xml file.
Background:
The project itself is a library apk project that uses and references another library APK project.
The error occurs when the project itself tries to initiate a new object that is a subclass of a super class contained on the referenced library apk project.
The Issue explained more below
The specific line of code that fails with the error is a static variable defined below:
protected static final String ANDROID_CONFIG_ID = LibraryApplication.getApplication().getString(R.string.api_checkout_config_id_override);
it fails with the following error:
java.lang.NoClassDefFoundError: com/jon/commonlib/R$string
commonLib is the referenced library apk if you are wondering.
Here is my 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 is empty");
}
} catch (IOException e) {
e.printStackTrace();
Assert.fail(e.toString());
}
}
}
The EventsTestHelper is the sub class for a super class called NetworkHelper which looks like 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 the latest for runing ,my unit tests.
If i was to run the code live and call and initiate the sub class, it works perfectly fine, no crashes
edit: Here is snippets of my 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: i have also tried to manually create a task that copies the r class for each dependency.
afterEvaluate { project ->
android.libraryVariants.each { variant ->
// workaround for missing R class for 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"
from { "build/generated/source/r/${variant.dirName}/$package_namespace_path" }
into { "build/generated/source/r/${variant.dirName}/com/jon/commonlib" }
// into { "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"
from { "build/generated/source/r/${variant.dirName}/$package_namespace_path" }
into { "build/generated/source/r/${variant.dirName}/android/support/v7/appcompat" }
// into { "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 itself is a library apk project that uses and references another library APK project.
For this type of projects exist an already known issue https://github.com/robolectric/robolectric/issues/1796 but you can workaround it.
The base issue is the android/gradle behaviour for library projects which is different compared to application projects. It just ignores to generate R classes from aar dependencies.
To workaround you can provide your own R class which already contains all dependencies R values. Here an example for the appcompat dependency
afterEvaluate { project ->
android.libraryVariants.each { variant ->
// one line for each aar dependency
tasks.getByName("assemble${variant.name.capitalize()}").dependsOn copyAppcompat
}
}
// copy it for each aar dependency and adjust it to your needs
task copyAppcompat(type: Copy) {
// replace the base package with yours (all after /r/debug/) which contains your R.class
from 'build/generated/source/r/debug/com/example/core'.replace("/", File.separator)
// replace the library packages with yours (all after /test/java/) with your aar dependency base package
into 'src/test/java/android/support/v7/appcompat'.replace("/", File.separator)
// also replace the package declaration or you will get compile errors
filter { line -> line.contains('package com.example.core;') ? 'package android.support.v7.appcompat;' : line }
include 'R.java'
}
An example project with your setup can be found at https://github.com/nenick/AndroidStudioAndRobolectric/tree/library-with-aar
Are you including the library in your testing classpath?
dependencies {
androidTestCompile(<reference to commonLib>)
}
I wasn't able to reproduce this in any way, but here are two things that might help.
Try using RobolectricGradleTestRunner instead of RobolectricTestRunner
You shouldn't need to put your other library in testCompile. So I think you can safely remove testCompile(name: 'commonLib-1.0 1', ext: 'aar')
Let me know in the comments if you have any updates after you try the different runner.

robolectric with gradle: package does not exist when using play-services

I want to write a unit test where the class to be tested uses at some places play-services. So far I could not make it work.
I am using gradle and my build.gradle file looks like this
apply plugin: 'com.android.application'
String[][] allowedFlavorCombinations = [
...
];
android.variantFilter { variant ->
boolean buildVariant = false;
for (int i = 0; i < allowedFlavorCombinations.length; i++) {
if(allowedFlavorCombinations[i][0].equalsIgnoreCase(variant.getFlavors().get(0).name)
&& allowedFlavorCombinations[i][1].equalsIgnoreCase(variant.getFlavors().get(1).name)) {
buildVariant = true;
}
}
variant.setIgnore(!buildVariant);
}
android {
compileSdkVersion 20
buildToolsVersion "20"
defaultConfig {
minSdkVersion 11
targetSdkVersion 20
versionCode=139
versionName="3.0"
}
sourceSets {
instrumentTest.setRoot('src/test')
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
}
lintOptions {
checkReleaseBuilds false
abortOnError false
}
signingConfigs {
release
}
buildTypes {
release {
minifyEnabled false
signingConfig signingConfigs.release
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = new File(output.outputFile.parent, output.outputFile.name.replace(".apk", "-" + defaultConfig.versionName + ".apk"))
}
}
}
}
if (project.hasProperty('storeFile') &&
project.hasProperty('storePassword') &&
project.hasProperty('keyPassword')) {
android.signingConfigs.release.storeFile = file(storeFile)
android.signingConfigs.release.storePassword = storePassword
android.signingConfigs.release.keyPassword = keyPassword
android.signingConfigs.release.keyAlias = keyAlias
} else {
buildTypes.release.signingConfig = null
}
flavorDimensions "client", "settings"
productFlavors {
...
}
}
sourceSets {
unitTest {
java.srcDir file('src/test/java')
resources.srcDir file('src/test/res')
}
}
configurations {
unitTestCompile.extendsFrom runtime
unitTestRuntime.extendsFrom unitTestCompile
}
dependencies {
compile 'com.android.support:appcompat-v7:20.0.0'
compile 'com.android.support:recyclerview-v7:21.0.0'
compile 'com.google.code.gson:gson:2.3'
compile 'com.google.android.gms:play-services:6.1.71'
compile 'com.android.support:support-v4:21.0.0'
compile 'com.nineoldandroids:library:2.4.0'
compile 'com.android.support:gridlayout-v7:21.0.+'
compile fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
unitTestCompile files("$project.buildDir/intermediates/classes/testbase/debug/")
...
unitTestCompile 'junit:junit:4.11'
unitTestCompile 'com.loopj.android:android-async-http:1.4.6'
unitTestCompile('org.robolectric:robolectric:2.3:jar-with-dependencies') {
exclude module: 'support-v4'
}
unitTestCompile 'com.google.android:android:4.1.1.4'
unitTestCompile 'org.mockito:mockito-core:1.10.8'
unitTestCompile 'org.powermock:powermock-api-mockito:1.6.1'
unitTestCompile 'org.powermock:powermock-module-junit4-rule-agent:1.6.1'
unitTestCompile 'org.powermock:powermock-module-junit4-rule:1.6.1'
unitTestCompile 'org.powermock:powermock-module-junit4:1.6.1'
unitTestCompile 'com.android.support:appcompat-v7:20.0.0'
unitTestCompile 'com.google.code.gson:gson:2.3'
unitTestCompile 'com.google.android.gms:play-services:6.1.71'
unitTestCompile 'com.android.support:support-v4:21.0.0'
unitTestCompile 'joda-time:joda-time:2.5'
unitTestCompile fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
instrumentTestCompile 'junit:junit:4.11'
instrumentTestCompile('org.robolectric:robolectric:2.3:jar-with-dependencies') {
exclude module: 'support-v4'
}
}
task unitTest(type:Test, dependsOn: [assembleDefault, ':AndroidUtilitiesLibrary:unitTest', ':AndroidUraLibrary:unitTest']) {
testClassesDir = project.sourceSets.unitTest.output.classesDir
classpath = project.sourceSets.unitTest.runtimeClasspath
}
check.dependsOn unitTest
Furthermore there is a topleve build.gradle file
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0'
}
}
subprojects {
apply plugin: 'android-sdk-manager'
}
allprojects {
repositories {
jcenter()
}
}
In my test class I merely try to create an instance of the class to be tested:
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.util.ActivityController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import com.google.android.gms.common.api.ConnectionCallbacks;
#RunWith(RobolectricTestRunner.class)
#Config(manifest = "./src/main/AndroidManifest.xml",emulateSdk = 18)
public class MyClass Test {
#Test
public void test() {
MyClass adapter = new MyClass(Robolectric.application, false);
//TODO
}
}
Running the test I get the following message:
error: package com.google.android.gms.common.api does not exist
import com.google.android.gms.common.api.ConnectionCallbacks;
Does someone have some experience in testing classes that use play-services with robolectric (using gradle)?

gradle espresso - Empty test suite

trying to run espresso integration-tests with gradle/Android-Studio - but no test is found:
package net.espresso_test;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
#SmallTest
public class AddTest extends ActivityInstrumentationTestCase2<MainActivity> {
public AddTest() {
super(MainActivity.class);
}
public AddTest(Class<MainActivity> activityClass) {
super(activityClass);
}
#Override
public void setUp() throws Exception {
super.setUp();
// Espresso will not launch our activity for us, we must launch it via getActivity().
getActivity();
}
#SuppressWarnings("unchecked")
#SmallTest
public void testAddItem() {
fail();
}
}
this is the build.gradle:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
apply plugin: 'android'
repositories {
mavenCentral()
maven {
url project.hasProperty('ligisMavenUrl') ? ligisMavenUrl : "https://raw.github.com/ligi/ligis-mvn-repo/master";
}
}
android {
compileSdkVersion 19
buildToolsVersion "19"
defaultConfig {
minSdkVersion 11
targetSdkVersion 19
testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner"
}
}
dependencies {
compile files('libs/socialauth-android-3.0.jar')
compile files('libs/volley.jar')
instrumentTestCompile files('libs/espresso-1.0-SNAPSHOT-bundled.jar')
instrumentTestCompile 'com.google.guava:guava:11.0.2'
compile 'org.ligi:AXT:0.21'
compile 'com.android.support:appcompat-v7:18.0.0'
compile 'com.android.support:support-v4:18.0.0'
compile 'com.google.android.gms:play-services:3.2.25'
compile 'com.squareup.dagger:dagger:1.1.0'
compile 'com.squareup.dagger:dagger-compiler:1.1.0'
compile 'com.jakewharton:butterknife:3.0.0'
}
have also tried a lot of other repos from github - all have the same problem - here is a hint that it could have to do something with guava ( which I do not use in this project ) - but no solution yet:
https://groups.google.com/d/msgid/android-test-kit-discuss/0e8bf175-498f-438e-b883-35b76bcede8d%40googlegroups.com
really stuck here - would love to get any hint or ideally a link to a repo where it is working ..
I think you'll find that guava is a dependency for Espresso.
https://code.google.com/p/android-test-kit/source/browse/#git%2Fbin%2Fespresso-dependencies%253Fstate%253Dclosed
You are using both the bundled espresso jar and a guava import which look like they contradict each other.
instrumentTestCompile files('libs/espresso-1.0-SNAPSHOT-bundled.jar')
instrumentTestCompile 'com.google.guava:guava:11.0.2'
The bundled version of espresso comes with guava 14.0.1.
Remove the surplus guava jar you have in the gradle test dependencies.
If this doesn't work can you also post the relevant section of you test manifest.

Categories

Resources