Android Studio - Junit 4 - Running code before ALL tests - android

I have an app to which I want to force the locale whenever the app is opened. So I will use Locale.setDefault(myCountryLocale). in the application's onCreate() method
Unit Tests don't start that class, so I want to be able to set the same locale whenever tests are started. Either by an extension or gradle script to setup the locale so that tests don't fail if whoever runs them uses another locale.

I know this is kinda old post but I faced this problem.
You can extends RunListener class and override the testRunStarted this code block will run only once before all your tests.
This listener will be added to you test manifest like this
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="YOUR_APP_PACKAGE">
<meta-data
android:name="listener"
android:value="YOUR_LISTENER_PACKAGE" />
</instrumentation>

Related

Issues using custom testInstrumentationRunner

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>

Add teardown block for single test in Android

In iOS there exists a tear block you can add to individual tests called addTearDownBlock and you put it inside a single test and it will only execute for that single test.
Does android have a similar version of this?
Unit testing in android is done with xUnit variation known as JUnit. If you are using JUnit 4.0, then use the following annotation:
#AfterClass //Will only execute once after all the tests in the class have exhausted
#After //Will run after every test
If you are using JUnit 5.0 then use the following annotation:
#AfterEach //Will run after every test
#AfterAll //Will only execute once after all the tests in the class have exhausted

How to run single test method in android instrumented test class and how to change edit configuration for this

I have written multiple test methods in a single android instrumented test class, when I am trying to run a single test method it will run all methods exists in that class.
I want to run only one.
Earlier I was able to run all, but somehow configuration settings have been changed
class HistoryTest{
#Test
fun openHistoryTest{
}
#Test
fun closeHistoryTest{
}
#Test
fun editHistoryTest{
}
}
I want to run a specific single test method say openHistoryTest.
Currently getting an error - the command line is too long shorten the command line for test "testname"
I updated Android Studio to canary and can run the whole class or a single method as instrumental test. Currently using AS 3.6 Canary 12.
Still doesn't work on Android Studio 3.5. I can't run each method as an
instrumental test, only the whole class.

Method setUp in android.test.AndroidTestCase not mocked

I'm trying to come to terms with the new unit test feature of Android Studio.
I've followed the instructions on http://tools.android.com/tech-docs/unit-testing-support. The description there explicitly mentions the 'Method ... not mocked' error and suggests to put the following into the build.gradle:
android {
// ...
testOptions {
unitTests.returnDefaultValues = true
}
}
This works in so far as the tests run when started from the command line with
gradlew test --continue
but not when I run the test class from Android Studio with rightclick -> run. This way, I get the same error again:
java.lang.RuntimeException: Method setUp in android.test.AndroidTestCase not mocked. See https://sites.google.com/a/android.com/tools/tech-docs/unit-testing-support for details.
at android.test.AndroidTestCase.setUp(AndroidTestCase.java)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Any ideas on how to solve this?
EDIT: The content of the test class doesn't really matter because the setUp of the test fails, I tried with the most simple class:
public class ContactFormToolTest extends AndroidTestCase {
public void testSOmething(){
assertEquals(false, true);
}
}
Also tried overriding setUp, makes no difference.
From: https://sites.google.com/a/android.com/tools/tech-docs/unit-testing-support#TOC-Method-...-not-mocked.-
The android.jar file that is used to run unit tests does not contain
any actual code - that is provided by the Android system image on real
devices. Instead, all methods throw exceptions (by default). This is
to make sure your unit tests only test your code and do not depend on
any particular behaviour of the Android platform (that you have not
explicitly mocked e.g. using Mockito). If that proves problematic, you
can add the snippet below to your build.gradle to change this
behavior:
android {
// ...
testOptions {
unitTests.returnDefaultValues = true
}
}
The new Unit Tests feature in Android Studio fakes the entire Android SDK so that you can run fast, Java-only tests, without needing to install your application on an Android device (this is similar to Robolectric). The general idea is that you mock all the responses from the Android SDK calls.
AndroidTestCase is used to run a test with the real Android SDK.
So, your issue is that you are trying to run an AndroidTestCase that depends on the Android SDK, but your test runner is launching the Unit Tests environment, which uses a fake Android SDK instead of a real one.
You need to choose one approach. If you want a pure unit test, then you probably should use a JUnit 4 test class instead of an AndroidTestCase. More instructions here:
https://developer.android.com/training/testing/unit-testing/local-unit-tests.html#build
As of SDK version 24, AndroidTestCase is deprecated
This class was deprecated in API level 24.
Use InstrumentationRegistry instead. New tests should be written using
the Android Testing Support Library.
You are supposed to use the Espresso framework for UI testing. There is a tutorial.

Android Studio - test configuration starts up app

I've got a couple of AndroidTestCase subclasses in separate packages of my project:
However, whenever I run Android Tests configuration from Android Studio, I see that my regular app is starting as well. I see that the onCreate method is fired up inside my Application class (which is really bad since I am loading some additional resources there).
Why is Android Studio/gradle running my app as well? Can I programatically detect if I am inside test or regular configuration? Can I stop my regular app from being booted before running tests?
In addition, when I am running tests in debug mode it doesn't stop on breakpoints placed inside the application's onCreate method. Why is this happening?
Edit:
Body of test class doesn't really matter, it can be something like:
public class SimpleTest extends AndroidTestCase {
public void testSample()
{
assertEquals(true, false);
}
}
Executing only this simple test fires up onCreate method inside application class.
Gradle console prints out:
Executing tasks: [:app:assembleDebug, :app:assembleDebugTest]
I guess that first task creates instance of my Application class - is it expected behavior?
Why is Android Studio/gradle running my app as well?
Can I stop my regular app from being booted before running tests?
AndroidTestCase is extension of JUnit TestCase which is aware of your android application. In case you don't need to test your android application and want to test plain java only you should use JUnit framework. Create regular JUnit tests, do not use android classes there and run JUnit test configuration like this:
You should treat AndroidTestCase as instrumentation tests which will build android app and run that tests on it. This is usefull with combination of Espresso and Robotium. Both are working on top of base android test classes and both will build and run your application before testing it. Real device or emulator is needed.
Use plain JUnit tests or Robolectric to test java on your desktop JVM.
Can I programatically detect if I am inside test or regular configuration?
You can use power of gradle to provide such info with autogenerated BuildConfig file.
At your build.gradle
android {
defaultConfig {
testPackageName "com.foo.test"
}
}
At your code:
BuildConfig.PACKAGE_NAME.equals("com.foo.test")
The AndroidTestCase is an unit test that unfortunately runs on the device (either virtual or real).
I think what you want to have is a UnitTestFramework that runs in the JVM (local on your machine). The TestFramework Robolectric can do this.
I have started a gitHub project to show how to setup the gradle test file and the project structure if you want to have UnitTests and InstrumentationTests side by side. If you want to look its AndroidGradleTests

Categories

Resources