I am trying to write a Robolectric test. I was following few tutorials where they seem to be using
#RunWith(RobolectricTestRunner::class)
#Config(constants = BuildConfig::class)
to setup the test, but in my case The parameter constants does not seem to resolve.
My Robolectric dependency looks like this:
testImplementation "org.robolectric:robolectric:4.0.2"
constants parameter is now deprecated see the doc :
constants
Deprecated.
If you are using at least Android Studio 3.0 alpha 5 please migrate to the
preferred way to configure builds for Gradle with AGP3.0
http://robolectric.org/getting-started/
The proper way to set up Robolectric per the documentation is :
android {
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
dependencies {
testImplementation 'org.robolectric:robolectric:4.1'
}
Robolectric is for unit test, not for androidTest, so please confirm that your test case is under src/test, NOT under src/androidTest.
Related
I'm having trouble creating a unit test without needing robolectric. I am using AndroidThreeTen.init(this) in my code and when I run my test if I disable robolectric I get an error:
org.threeten.bp.zone.ZoneRulesException: No time-zone data files registered
and if I leave it enabled I get this:
[Robolectric] com.mycomp.,yapp.utilities.log.LogTest.on Calling function w it returns an Int: sdk=28; resources=BINARY
I have tried using testImplementation ‘com.jakewharton.threetenabp:threetenabp:1.1.0’
made no difference. I have AndroidThreeTen.init(this) called in my application and testApplication. any ideas?
this is my test
#Test
fun `on Calling function i it returns an Int`() {
assertThat("Returned class is not an Int", Log.i("Test", "Test"), isA(Int::class.java))
assertThat("Returned Int is not 0", Log.i("Test", "Test"), `is`(0))
}
Or do I have to use robolectric because of this?
(Side note: Log is not the util.log from android but my own class) (edited)
JVM unit tests don't run on Android runtime. Instead of ThreeTenABP, you can just use ThreeTenBP directly to get the same API initialised for a regular JVM.
In my project build.gradle I use a setup like:
implementation "com.jakewharton.threetenabp:threetenabp:${threetenabpVersion}"
testImplementation("org.threeten:threetenbp:${threetenbpVersion}") {
exclude module: "com.jakewharton.threetenabp:threetenabp:${threetenabpVersion}"
}
where
threetenabpVersion = '1.2.0'
threetenbpVersion = '1.3.8'
This uses ThreeTenBP via ThreeTenABP normally, but in unit test configuration it adds TreeTenBP directly as a dependency, with its init code. Cannot remember exactly why I put in the exclude rule; it's been like that for a few years already.
For some reason #laalto solution didn't work for me. Here's what worked instead:
dependencies {
...
implementation "com.jakewharton.threetenabp:threetenabp:$threetenabp_version"
testImplementation "org.threeten:threetenbp:$threetenbp_version"
}
configurations.testImplementation {
exclude group: 'com.jakewharton.threetenabp'
}
Android Studio 3.0 Beta2
classpath 'com.android.tools.build:gradle:3.0.0-beta3'
testCompile 'org.robolectric:robolectric:3.4.2'
Test class that I am using that fails to run:
#Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.LOLLIPOP)
#RunWith(RobolectricTestRunner.class)
public class RecipeAdapterTest {
private MainActivity activity;
#Before
public void setup() {
activity = Robolectric.setupActivity(MainActivity.class);
/* Also tried this same Error
activity = Robolectric.buildActivity(MainActivity)
.create()
.resume()
.get();
*/
}
#Test
public void testActivityShouldNotBeNull() {
assertThat(activity, is(notNullValue()));
}
}
This is the stack trace of the error:
android.content.res.Resources$NotFoundException: String resource ID #0x7f0c0020
at android.content.res.Resources.getText(Resources.java:274)
at android.content.res.Resources.getString(Resources.java:360)
at android.content.Context.getString(Context.java:376)
at org.robolectric.shadows.ShadowActivity.getActivityTitle(ShadowActivity.java:100)
at org.robolectric.shadows.ShadowActivity.callAttach(ShadowActivity.java:110)
at org.robolectric.android.controller.ActivityController.attach(ActivityController.java:56)
at org.robolectric.android.controller.ActivityController.of(ActivityController.java:25)
at org.robolectric.Robolectric.buildActivity(Robolectric.java:98)
at org.robolectric.Robolectric.buildActivity(Robolectric.java:94)
at org.robolectric.Robolectric.setupActivity(Robolectric.java:102)
at me.androidbox.busbybaking.adapters.RecipeAdapterTest.setup(RecipeAdapterTest.java:63)
In the Edit Configurations I have set the Working Directory to $MODULE_DIR$
Many thanks for any suggestion.
As mentioned by an engineer from Google team (most possibly Xavier Ducrohet), Robolectric has issues with AAPT2:
Robolectric is not compatible with aapt2.
Two options here.
First option - follow Robolectric guidelines for Android Studio 3.0+
Add the following to your build.gradle:
android {
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
Annotate your test with the Robolectric test runner:
#RunWith(RobolectricTestRunner.class)
public class SandwichTest {
}
Second option: disable AAPT2 adding following line into gradle.properties file:
android.enableAapt2=false
The Robolectric documentation states that the following configuration should be used with Android Studio 3.x:
android {
testOptions {
unitTests.includeAndroidResources true
}
}
(for anyone that might be looking for a solution to a similar problem)
Be sure to use
RuntimeEnvironment.application
and not:
RuntimeEnvironment.systemContext
when you're trying to resolve resources "manually".
That's one case in which Resources$NotFoundException might show up with Robolectric.
Not a direct answer to the question, but if you are testing something that needs a context to query resources against I have found the following to work quite well:
ApplicationProvider.getApplicationContext()
(or RuntimeEnvironment.application -- but this is deprecated in favor of the above)
If your build fails due to an AAPT2 resource processing issue or you want to use Roboelectric, you can disable AAPT2 by setting android.enableAapt2=false in your gradle.properties file and restarting the Gradle daemon by running ./gradlew --stop from the command line.
Official guideline Android Studio 3.0 Release
I was using espresso, and for that you needed to use app resources, not test resources.
So instead of
InstrumentationRegistry.getInstrumentation().context.resources.getString("key")
I used
activityRule.activity.getString("key")
In my case the following solved my issue:
"Problem is related to android studio. Go to 'Run' -> 'Edit configurations...' and change 'Working directory' value to
$MODULE_DIR$
Run your tests.
More info here under 'Building with Android Studio'."
reference: https://github.com/robolectric/robolectric/issues/2653
You can also try #Config(manifest = "<projectFolder>/src/main/AndroidManifest.xml") in the case that you can not simply include the resources as some projects tests will fail with that included.
I have an android project with unit and integration tests in the same folder. If I run ./gradlew test all of them are run, but I just need to exclude the cucumber tests from running, at the moment I just need to actually exclude to run the class with the annotation #RunWith(Cucumber.class).
Any suggestions?
The usual way of adding a test closure like below does not work for some reason with gradle android plugin:
test {
exclude 'com/example/MyTest.*'
}
Instead I have found the following option. Use the #Ignore annotation on your test(s). You can also conditionally ignore the test (e.g. based on a system property like RUN_AUTOMATION_TEST=false) using this answer
If you are using spock rather than junit then use something like this:
#IgnoreIf( {System.getProperty('RUN_AUTOMATION_TESTS') == null} )
public class MainScreenSpec extends BaseUiAutomationSpec {
}
I am new to Android instrumented unit tests. I have a simple test that looks like this. This is in instrumented tests; before I really write an actual instrumented test, I just want to test a simple one:
#RunWith(AndroidJUnit4.class)
#SmallTest
public class AddressBookKeepingInstrumentedTest {
public static final String TEST_STRING = "This is a string";
public static final long TEST_LONG = 12345678L;
#Test
public void test_simple() {
assertEquals(2,1+1);
}
}
When I run this, I get the following error:
junit.framework.AssertionFailedError: No tests found in com.example.myfirstapp.AddressBookKeepingInstrumentedTest
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:191)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:554)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1729)
Tests ran to completion.
Gradle build passed with success before this.
Any ideas why this is happening?
Please add the following into your build.gradle and put your test classes into androidTest folder
android {
defaultConfig {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
I recently tried the accepted answer, but it gave me a process crash error when trying to run. If you get this you should use:
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Source: Instrumentation run failed due to 'Process crashed.'
The typical cause of this can be seen as an exception in Logcat.
I had a specific issue regarding an instrumented multidex run on < API 21, I had to both install MultiDex on a subclass of androidx.test.runner.AndroidJUnitRunner, and override:
AndroidJUnitRunner::createTestRequestBuilder
TestRequestBuilder::createClassPathScanner
ClassPathScanner::getClassPathEntries with the implementation as:
Unzip and extract the dex files from the APK
Run dexlib2 to obtain the type names.
Convert from the type names to a readable format: Ljava/lang/String; -> java.lang.string
This is because ClassPathScanner uses dalvik.system.DexFile, which on API 16, only reads APKs, and then only reads classes.dex
Another reason to get this error message is when you have an Android App implemented with Java and test cases implemented with Kotlin. If that is the case, be sure you have the following lines in your gradle file:
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
This post helped me, just rename your tests methods with "test...", like testMethod()
Make sure you added the correct dependencies in the app's build.gradle file:
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
The Expresso one is required for any instrumented test even if you don't use it.
I'm using the robolectric-gradle-plugin for robolectric unit tests. I don't want to fail a build on failed tests. Is there a way in DSL or a property not to fail a test on the build similar to -DtestFailureIgnore=true on the Surefire Maven plugin?
I've tried:
robolectric {
ignoreFailures = true
}
and
robolectric {
ignoreFailure = true
}
and -DignoreFailure=true on the command line.
I can't seem to find any documentation of how to do this, or any reference to ignoring tests in the source code.
answering very old question, so that it might help others who bump into here
testOptions {
unitTests.all {
setIgnoreFailures(true)
}
}
I would suggest not to continue building an APK if there are any failing tests. But if you want to build an APK without testing the only way right now is to use gradle build -x test[1]. This will run build and not run any tests.
[1]http://www.gradle.org/docs/current/userguide/userguide_single.html#sec:excluding_tasks_from_the_command_line
try without '='
robolectric {
ignoreFailures true
}