I am doing the unit testing on android studio, I create a test case in test class and on every time when I run that it give different output but when I debug it give me fine out put.It may be problem of caching or something else. I have also tried Invalidate studio and clean project but still occurring. Please Help.
In your #Before method, make sure to use Intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) to make sure the app is not already running in the background of your test when you begin testing. This could be what is introducing your cache issue.
to clarify, your #Before method should look something like this:
#Before
public void setup() {
//Initialize UiDevice instance
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
mDevice = UiDevice.getInstance(instrumentation);
mDevice.pressHome();
Intent intent = new Intent("com.REDACTED.auto.diagnostics.dealer.MAIN");
intent.setClassName("com.REDACTED.auto.diagnostics", "com.REDACTED.auto.diagnostics.dealer.MainActivity");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Context context = InstrumentationRegistry.getContext();
context.startActivity(intent);
}
There are simpler ways to do this if you have the source code, however in my case I did not
Related
I am using Espresso with Kotlin for the UI test automation. I am trying to find a proper way to restart the app during the test and start it again, so the test scenario is the following:
start the app, go to login page
force close the app and open it again (basically restart it)
check some stuff etc
The way our UI tests are organized:
there is a test class where I have rules
val intent = Intent(ApplicationProvider.getApplicationContext(), MainActivity::class.java)
.putExtra(UI_TEST_INTENT, true)
#get:Rule
val rule = ActivityScenarioRule<MainActivity>(intent)
there Before/After functions and tests functions in this class
What I want is to have generic restartApp function in separated class, let's say TestUtils and to be able to call it at any point of time, when is needed.
So far I didn't find a solution. There are some similar questions on stackoverflow, but I am not sure I understand how to work with the answers I found, like this:
with(activityRule) {
finishActivity()
launchActivity(null)
}
Since ActivityTestRule is deprecated and documentation asking to use ActivityScenarioRule, I tried this:
#get:Rule
val rule = ActivityScenarioRule<MainActivity>(intent)
private fun restart() {
rule.scenario.close()
rule.scenario.recreate()
}
but it gets java.lang.NullPointerException
another option is
private fun restart() {
pressBackUnconditionally()
Intents.release()
ActivityScenario.launch<MainActivity>(intent)
}
it works, app restarts but I can not interact with the app anymore, because for some reason there are two intents running now
Would be great to get an answer I can work with (I am quite new to Espresso)
Cheers
The solution is found:
private fun restart() {
Intents.release()
rule.scenario.close()
Intents.init()
ActivityScenario.launch<MainActivity>(intent)
}
Seems like the author's answer has some excess code. The following is enough
activityScenarioRule.scenario.close()
ActivityScenario.launch(YourActivity::class.java, null)
I have a testsuite which has mutiple testcases in a class
every test case is isolated
So when i execute the testsuite class i want to restart the app for every testcase
How do i relaunch application from start for every individual test case in Espresso
Thanks in advance
#Test
public void testcase1() {
//from first screen
}
#Test
public void testcase2() {
//from first screen
}
There is another stack overflow answer that seems to answer this question. If you were looking to do that in Kotlin though I converted the answer to relaunch multiple times for different tests.
#RunWith(AndroidJUnit4::class)
class ExampleEspressoTest {
#get:Rule
val rule = ActivityTestRule(
activityClass = MainActivity::class.java,
initialTouchMode = false,
launchActivity = false) //set to false to customize intent
#Test
fun testCustomIntent() {
val intent = Intent().apply {
putExtra("your_key", "your_value")
}
rule.launchActivity(intent)
//continue with your test
}
}
If you need to start a method/test and when it's finished clear data and start the next one, you should use commands.
Look at this documentation: https://developer.android.com/studio/test/command-line
I'm using this command:
./gradlew testVariantNameUnitTest --tests *.sampleTestMethod
There could be several ways to do this but we wanted a way that works both locally as well as google fire base test lab, so ended up with using configuration in build.gradle file under default config.
defaultConfig{
testInstrumentationRunnerArguments clearPackageData: 'true'
}
Reference: https://developer.android.com/training/testing/junit-runner#ato-gradle
Also you use these runner arguments for configuring different tests you wanted run based on build variants or other config options, look at my post if you want more detail.
I searched this question but didn't find answers.
Suppose there is a system app, which is installed together with android system, e.g. Dialer app.
Now I want to unit-test or instrumentation-test this app. I don't want to use AOSP Android.mk. Are there alternative ways? e.g. Can I create a gradle project to test it?
For instrumentation tests I personally create an independent app that consumes uiautomator: https://developer.android.com/topic/libraries/testing-support-library/index.html#UIAutomator
This allows simulation of a user:
#org.junit.Test
public void testCheckContact() throws InterruptedException {
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
assertThat(device, notNullValue());
device.pressHome();
Context context = InstrumentationRegistry.getInstrumentation().getContext();
Intent intent = context.getPackageManager().getLaunchIntentForPackage("systempackageName");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intent);
...
...
PhoneActivityPage phoneActivityPage = new PhoneActivityPage();
phoneActivityPage.clickContacts();
assertEquals("Contacts", phoneActivityPage.getSelectedTab());
}
Where you can define PhoneActivityPage and the interface in a separate class within this independent test project.
I hope this helps.
You can use the UiAutomator system to test arbitrary apps, including system ones. However, the inputs and outputs are somewhat limited.
I'm using Android Studio AI-141.1972460 with JUnit 4 and am trying to write a simple JUnit test for an Activity:
public class GameActivityTest extends ActivityUnitTestCase<GameActivity> {
public GameActivityTest() {
super(GameActivity.class);
}
#Before
public void setUp() throws Exception {
super.setUp();
Intent intent = new Intent(getInstrumentation().getTargetContext(), GameActivity.class);
startActivity(intent, null, null);
. . .
The code compiles but getInstrumentation is returning null so I'm getting a NullPointerException there.
I tried using ActivityInstrumentationTestCase2 instead of this approach, but getActivity is likewise returning null in that case, too.
I assume this is somehow related to mocking? I have
testOptions {
unitTests.returnDefaultValues = true
}
in my build.gradle file as well as
testCompile 'org.mockito:mockito-core:1.9.5'
Do I need to mock out an Application object or something like that?
Thanks for your help.
Looks like I was trying to run my test as a "JUnit Test" (per the instructions at http://tools.android.com/tech-docs/unit-testing-support) and not as an "Android Test".
When I set it up as an "Android Instrumentation Test" (the difference being the Test Artifact setting in the Build Variants), this worked okay.
As a "JUnit Test", I was able to work around this and get my Activity object set up using Robolectric.
I run my Android tests by running a test implementation which "derives" from a library project (because I have a multi module project with baselib and "concrete app projects"). The test implementation is one of these concrete app projects and is launched by an InstrumentationTestCase. In this test case I mock several parts from the library project by RoboGuice. That means I run a "real" implementation of my baselib with mocked classes (like persistence handling, database handling and so on). To be able to do that, every single test case has to close and restart the whole test instance, because I can't start the same app twice on the device. These test are more integration tests than Junit tests, because I test some kind of workflows, but there is no other possibility to test that, because the possibilities with JUnit on Android testing seem to be very limited.
At the moment I can only run one test case at the same time, because if I run more than 1, the whole test is hanging. I already checked if it's the configuration change (see private method) which causes my test to freeze, but this is not the cause. See my attempts in tearDown method. I can't run
getInstrumentation().finish(0, new Bundle());
because I get
Test failed to run to completion. Reason: 'Test run failed to
complete. Expected 3 tests, received 1'
I also cannot run
getInstrumentation().callActivityOnDestroy(activity);
because I don't have an Activity here. Moreover the Activity "StartTestActivity" which is launched at startup is not the same Activity which runs when the test is finished because StartTestActivity launches another Activity "MainMenuActivity" which is running at the end of the test. I already thought about using Instrumentation.ActivityMonitor but this doesn't provide the needed functionality.
Nevertheless I want to somehow start with the same test conditions at every test case as the whole test itself does at startup, but I'm not sure what InstrumentationTestCase is doing in the background, so I don't know how to restart the whole instrumentation setup. I somehow need to stop and restart the test instance, or maybe there is a better solution? Any ideas?
(by the way: every test itself runs fine, so it's no problem of the test ifself).
public class WorkflowModule1Test extends InstrumentationTestCase
{
private PersistenceManagerMock persistenceManager;
#Override
protected void setUp() throws Exception
{
super.setUp();
}
#Override
protected void tearDown() throws Exception
{
super.tearDown();
if (persistenceManager != null)
{
persistenceManager.clear();
}
}
public void testSaveLocaleEN() throws PersistenceException
{
updateLocaleConfiguration(Locale.ENGLISH);
Intent intent = new Intent(getInstrumentation().getContext(), StartTestActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getInstrumentation().startActivitySync(intent);
persistenceManager = (PersistenceManagerMock)RoboGuice.getInjector(ContextProvider.getApplication()).getInstance(IPersistenceManager.class);
List<Entity> entities = persistenceManager.getEntities();
assertTrue(entities.size() == 1);
assertTrue(entities.get(0) instanceof LanguageUsageRel);
assertTrue(((LanguageUsageRel)entities.get(0)).getLanguageId().equals("EN"));
}
public void testSaveLocaleDE() throws PersistenceException
{
updateLocaleConfiguration(Locale.GERMAN);
Intent intent = new Intent(getInstrumentation().getContext(), StartTestActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getInstrumentation().startActivitySync(intent);
persistenceManager = (PersistenceManagerMock)RoboGuice.getInjector(ContextProvider.getApplication()).getInstance(IPersistenceManager.class);
List<Entity> entities = persistenceManager.getEntities();
assertTrue(entities.size() == 1);
assertTrue(entities.get(0) instanceof LanguageUsageRel);
assertTrue(((LanguageUsageRel)entities.get(0)).getLanguageId().equals("DE"));
}
private void updateLocaleConfiguration(Locale locale)
{
Locale.setDefault(locale);
Configuration configuration = new Configuration();
configuration.locale = locale;
getInstrumentation().getContext().getResources().updateConfiguration(configuration, getInstrumentation().getContext().getResources().getDisplayMetrics());
}
}
I think if you extended ActivityInstrumentationTestCase2 instead this would solve a lot of your problems.
Another note: Put your tear down logic before the super.tearDown() call.
I found the solution on my own. I have to set these two flags.
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);