I have the following test for Android:
#RunWith(AndroidJUnit4::class)
class LogoutFragmentTest {
#Test
fun testEventFragment() {
val scenario = launchFragment<LogoutFragment>(
initialState = Lifecycle.State.INITIALIZED
)
scenario.onFragment { fragment ->
assertThat(fragment.m_Context).isNotNull()
}
}
}
I am launching the test from the androidTest folder (with right mouse click)in the project with the option 'Run All tests'. The test launches an emulator, performs some tasks, it announces 'Connected to process .. on device ..' and then starts the task connectedDebugAndroidTests and remains so for a while.
Then it displays a message explaining where the test results are.
Test results saved as file ...
In the test error log I have the following information:
INSTRUMENTATION_RESULT: stream=
Test results for InstrumentationTestRunner=
Time: 0.0
OK (0 tests)
INSTRUMENTATION_CODE: -1
Can anyone please help ?
I have managed to solve this:
I needed to configure the runner in the build.gradle file:
defaultConfig {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
Related
I created a custom Gradle task for running from terminal in a separate file named feature.gradle, based on this answer and Gradle docs
task("withFeature", JavaExec::class) {
group = "myCustomTasks"
main = "com.example.calculator"
classpath = sourceSets["main"].runtimeClasspath
args(feature)
}
and register task in Gradle
tasks.register("withFeature")
feature is a property (string) that I want to pass into test (for now it's unit test, but later it would be android UI test)
#Test
fun getPackArgs() {
val property = System.getProperty("feature")
Assert.assertEquals("default", property)
}
But when i write next command, where -Pfeature=default is what i wants to pass into code
./gradlew test withFeature -Pfeature=default
test fails, and System.getProperty("feature") is null :
expected:<default> but was:<null>
Expected :default
Actual :null
Can anyone elaborate what i am doing wrong while running task with argument, which should pass into test package ?
Thanks in advance
I've not found any post on Stack Overflow that helped, so I'm posting my own question.
I have a custom testInstrumentationRunner that when set doesn't run any tests.
The logs says:
App restart successful without requiring a re-install.
Running tests
adb shell am instrument -w -m --no-window-animation -e debug false -e class 'com.my.app.MyFragmentTest' com.my.app.debug.test/com.my.app.CustomTestRunner
Connected to process on device
When running the normal androidx.test.runner.AndroidJUnitRunner the tests run, but fail, because I need the custom runner.
The runner is set up like the androidx one, in:
defaultConfig {
// testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner
testInstrumentationRunner "com.my.app.CustomTestRunner"
}
It's also located in the com.my.app package in androidTest-folder
The code for the runner is:
package com.my.app
import ...
class CustomTestRunner: AndroidJUnitRunner() {
override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application {
DexOpener.install(this)
Timber.i("This should print hopefully")
return super.newApplication(cl, ApplicationTest::class.java.canonicalName, context)
}
}
Not sure if it matters, but here's the code for the application class, which extends the application class used for the app itself:
package com.my.app
class ApplicationTest: MyApplication() {
override fun onCreate() {
super.onCreate()
appContext = applicationContext
initializeDependencyInjection()
}
override fun initializeDependencyInjection() {}
}
I have a test-case I'm trying to run, which contains 7 tests. The androidx runner fails on 7/7 tests. But when I run with the custom runner, I get duration 0ms and 0/0 tests.
So it seems like Android isn't detecting this runner. I also get the same results using a random name in the testInstrumentationRunner, like testInstrumentationRunner "not.a.TestRunner"
I'm sure you've already solved the issue or switched jobs to growing potatoes or something more productive, but I just spent my whole morning debugging this same exact scenario and managed to find a solution:
The custom instrumentation runner you have is not ignored, but there is something broken in your custom Test Application initialization. Probably in your replacement dependency injections, like it was in my case. When you run the tests using the custom runner, the custom Test Application silently crashes immediately, but this is not indicated in the test results or in any other easily visible place. The crash stack trace is, however, accessible in logcat. So solve that first, and then try using your custom test runner again.
Do not mix between Instrumentation Tests and Unit Tests:
Unit Tests
Unit tests runs in local JVM and minimizes the execution time.
Unit Tests cannot test UI of the app without mocking activity objects.
Unit test are used for white box testing for testing code.
Most of the time Unit Tests are written by Developers.
You don’t need a device connected for execution of Unit Tests.
Instrumentation Tests
Instrumentation tests are used for black box testing.
It is used to test GUI of the application along with its functionality in real environment.
For execution of Instrumentation tests you need a device /emulator on which the application is first installed and then tests are executed.
Automation Testers are involved in writing instrumentation framework.
When testing a library module, you can link the test application in src/androidTest/AndroidManifest.xml:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:name="com.my.app.ApplicationTest"/>
</manifest>
I am following the steps exactly as mentioned here to create instrumentation unit test cases. This is my Test class in the androidTest->Java->com.mypackage.name package
#RunWith(AndroidJUnit4.class)
#SmallTest
public class Test {
private List<String> list;
#Before
public void initList(){
list = new ArrayList<>();
}
#org.junit.Test
public void searchPlace() {
assert list.size() == 0;
}
}
But when I execute this test case, I get a message saying
Process finished with exit code 1
Class not found: "com.package.base.Test"Empty test suite.
Is there anything that I am doing wrong?
I've seen this error when the test instrumentation runner isn't set correctly. It should be set to android.support.test.runner.AndroidJUnitRunner in the build file. Also double-check the class package name is correct in the test configuration.
This happens if you Cut-Paste the test from Unit to Instrumental.
Simply goto Main menu -> Run -> Debug -> Edit config...
Delete old and broken tests.
And re-run.
In Android Studio when I debug instrumentation test, the test won't stop on any breakpoint. Debugging unit tests works. I have a simple instrumented test that only checks if username edittext is displayed:
#RunWith(AndroidJUnit4.class)
public class LogonActivityTest {
#Rule
public ActivityTestRule<LogOnActivity> mActivityRule = new ActivityTestRule<>(LogOnActivity.class, true, false);
#Before
public void setUp() throws Exception {
mActivityRule.launchActivity(new Intent()); // breakpoint here
}
#Test
public void testSimple() throws Exception {
onView(withId(R.id.act_logon_et_username)).check(matches(isDisplayed())); // breakpoint here
}
}
In build.gradle I have properly set
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
How can I debug instrumented tests? I'm using Espresso, Mockito and Dagger 2.
You can solve this a couple of ways Tomask.
You can pass the option -e debug true in the configuration for your test if you're invoking the test from the command line.
Otherwise, and more simply, you should choose Debug instead of Run when starting your tests from android studio. If you click Run for your test from android studio, the option -e debug false gets set and the test(s) will not stop execution at breakpoints.
Hope this helps!
For me, switching to "Run Android instrumented Tests using Gradle" works fine.
Go to Android Studio -> Preferences and toggle this option.
If it is already enabled, try disabling it and hope for the best.
I try to run an Instrumentation Test for a certain flavor of my android app and always get this:
Test running failed: Unable to find instrumentation info for: ComponentInfo{<packackename>/android.support.test.runner.AndroidJUnitRunner}
Empty test suite.
This happens only in a certain productFlavor where I had to change the packagename in the build.gradle "manually" with:
applicationVariants.all { variant ->
def flavorName = variant.getVariantData().getVariantConfiguration().getFlavorName()
def mergedFlavour = variant.getVariantData().getVariantConfiguration().getMergedFlavor();
if (flavorName.toLowerCase().contains("foobar")) {
mergedFlavour.setApplicationId(mergedFlavour.getApplicationId() + ".foobar")
}
}
I already tried to do the same thing in the android-testing.gradle but actually all packagenames are looking fine:
Installing de.test.foobar.debug
DEVICE SHELL COMMAND: pm install -r "/data/local/tmp/de.test.foobar.debug"
pkg: /data/local/tmp/de.test.foobar.debug
Success
Installing APK:
Uploading file to: /data/local/tmp/de.test.foobar.debug.test
Installing de.test.foobar.debug.test
DEVICE SHELL COMMAND: pm install -r "/data/local/tmp/de.test.foobar.debug.test"
pkg: /data/local/tmp/de.test.foobar.debug.test
Success
If I remove the "manual" change of the packagename of this specific productflavor, all tests are executed fine.
I already tried to change the instrumentationRunner and made sure that it is the same in the configuration of the test execution - but unfortunately without luck...
Is there maybe a possibility to override the changed applicationId if the test is executed?
Thanks for every input!
if you recently upgraded to Android Studio 2.x and have enabled MultiDex (instant run need it at some point), you need to add the following in your gradle.build
defaultConfig {
...
multiDexEnabled true // <- if you have this you need the following
testInstrumentationRunner "com.android.test.runner.MultiDexTestRunner"
...
}
The testApplicationId needs to match the applicationId for each flavor you modify so the Test Runner can find the tests. You can do this by using testVariants along with applicationVariants.
Something like this in your case:
testVariants.all { variant ->
def flavorName = variant.getVariantData().getVariantConfiguration().getFlavorName()
def mergedFlavour = variant.getVariantData().getVariantConfiguration().getMergedFlavor();
if (flavorName.toLowerCase().contains("foobar")) {
mergedFlavour.setApplicationId(mergedFlavour.getApplicationId() + ".foobar")
}
}