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.
Related
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.
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'm trying to replace my Espresso registerIdlingResources and unregisterIdlingResources deprecated method by using IdlingRegistry method according to Android documentation.
Some of my tests worked before the update and no longer work now. These tests work unitarily, but not together.
I noticed that there is a little difference with the old version (of Espresso class), this line is not present in IdlingRegistry class :
baseRegistry.sync(IdlingRegistry.getInstance().getResources(), IdlingRegistry.getInstance().getLoopers());
I think this sync method is very important for my custom IdlingResource...
How can I sync my looper without this line?
Edit: I use EspressoCore 3.0.1 with runner/rules 1.0.1
Edit2: Link of documentation who has been specify deprecation : Here and Here.
Be sure to run the latest version of androidx.test
If your tests run one at a time, but fail when run together, Android Test Orchestrator ("ATO") can solve that problem.
ATO runs each test method in a new process, so any in memory state is cleared.
From the docs, the basic gradle setup is:
android {
defaultConfig {
...
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// The following argument makes the Android Test Orchestrator run its
// "pm clear" command after each test invocation. This command ensures
// that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true'
}
testOptions {
execution 'ANDROIDX_TEST_ORCHESTRATOR'
}
}
dependencies {
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestUtil 'androidx.test:orchestrator:1.3.0'
}
The docs also include setup for installing and using Android Test Orchestrator without gradle.
You can also use ATO on Firebase Test Lab:
via web UI
via CLI
If you still have problems with your IdlingResources you can try the busybee library which simplifies using IdlingResources and makes them easier to debug.
(disclaimer, I am a maintainer of that library)
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 want to start writing unit tests for my applications but I cannot get one simple test to run.
I have created a small application just to try how the unit test should be setup and run, but no test is actually run and I get 'Empty test suite'.
I am using Android Studio 0.6.1 with gradle 1.12
Here is my folder structure:
MyActivityTest.java
package com.vist.testableapp.tests;
import android.content.Intent;
import android.test.ActivityUnitTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.widget.Button;
import com.vist.testableapp.MyActivity;
import com.vist.testableapp.R;
public class MyActivityTest extends ActivityUnitTestCase<MyActivity>
{
public MyActivityTest(Class<MyActivity> activityClass)
{
super(activityClass);
}
Button btn1;
#Override
public void setUp() throws Exception
{
super.setUp();
startActivity(new Intent(getInstrumentation().getTargetContext(), MyActivity.class), null, null);
btn1 = (Button)getActivity().findViewById(R.id.button1);
}
#SmallTest
public void testFirst()
{
assertEquals("Btn1",btn1.getText());
}
}
application's build.gradle
apply plugin: 'android'
android {
compileSdkVersion 19
buildToolsVersion "19.1.0"
defaultConfig {
applicationId "com.vist.testableapp"
minSdkVersion 15
targetSdkVersion 15
versionCode 1
versionName "1.0"
testApplicationId "com.vist.testableapp.tests"
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
Could anyone point out what am I doing wrong or what I am missing?
I searched in SO but none of the answers helped me.
The constructor should look like this:
public MyActivityTest()
{
super(MyActivity.class);
}
I will need to learn not to rely so much on the IDE's code template that provided constructor with parameter.
This was resolved thanks to a colleague and http://siemprepreguntando.blogspot.de/2013/07/running-tests-test-running-startedtest.html
I also ran into "empty test suite" problem recently. After checking a few similar questions and answers, and my problem, I can possibly conclude that the problem results from an error preventing the tests being added to the test suite, such as an error in static initialization.
For example I'm using a popular approach to adding all tests as shown below, but it's the same scenario with different approaches to adding test cases to the suite:
public class FullTestSuite extends TestSuite {
public static Test suite() {
return new TestSuiteBuilder(FullTestSuite.class)
.includeAllPackagesUnderHere().build();
}
public FullTestSuite() {
super();
}
}
And apparently my test file had a problem in a static {} block which prevented .includeAllPackagesUnderHere() to run successfully.
So I would suggest anyone facing this error to first check your app logs to see if your test runs into a problem that prevents test cases being added to the test suite (like similar examples of wrong constructor being called or static initialization problems).
In my case, the "empty test suite" message was directly related to the target API Level of the Android Emulator I was running. I had set up an emulator with API level 19 and was using that while trying to run my instrumentation tests. I also had just recently migrated my codebase to use the JUnit4 framework along with the AndroidJUnitRunner instrumentation runner.
I was banging my head against the wall for a while before I started to look into issues with the actual emulator. Sure enough, as soon as I set up an emulator with API Level 23, the tests started to run fine.
Further experimentation found that my tests ran fine on API Level 22 & 23 emulators, but not on anything below that. I suspect it has something to do with my test dependencies and minimum API level requirements.
I'll update this answer if I discover more.