I have 2 activities, the first one is the startup one which in it's create method causes the second one to be launched, always.
My Robolectric tests pass fine
Activity
public class LoginActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loginview);
Intent intent = new Intent(this,MainActivity.class);
startActivity( intent );
}
I know my activity works fine cause it launches in my device and on the emulator
My Robolectric tests
public void testLoginFirstTime() throws Exception
{
LoginActivity activity = new LoginActivity();
activity.onCreate(null);
assertThat(activity, new StartedMatcher(MainActivity.class));
}
My Robotium test
public void setUp() throws Exception {
solo = new Solo(getInstrumentation(), getActivity());
}
public void testLoginFirstTime() throws Exception
{
solo.assertCurrentActivity("Expected MainActivity to launch", MainActivity.class);
}
What is wrong with my robotium assertion? it always thinks the current activity is login one even though as I watch the emulator/device I can see that Robotium does actually launch the MainActivity but it doesn't appear to know that the new activity has been launched.
Edit: Meant to say if I add a button to my login view and launch the new activty via a button click then Robotium performs the click and detects the new activity has been launched ok.
Edit:
Looks like its a Robotium limitation
http://groups.google.com/group/robotium-developers/browse_thread/thread/79a70038c16e35e6
However it still leaves me with the issue of how to test my app with robotium the same way as a user will use it, ie, not cheating and starting in a different activity :(
You need to use the constructor solo = new Solo(Instrumentation instrumentation) and then after you have created the Solo object you call getActivity() in order to start the first Activity. Then it will work.
Related
I want to access multiple Activity in my Instrumental testing.
e.g Login -> Search-> Listing-> Detail Activity
I have achieved till 'Listing activity' but i want to go for Listing Activity Element[1]'s Detail page.
Below is my code for
#RunWith(AndroidJUnit4.class)
public class ContactSearchScreeenTest extends ActivityInstrumentationTestCase2<ContactSearchScreen> {
public ContactSearchScreeenTest() {
super(ContactSearchScreen.class);
}
#Rule
public ActivityTestRule<ContactSearchScreen> mActivityRule =
new ActivityTestRule<>(ContactSearchScreen.class);
#Override
protected void setUp() throws Exception {
super.setUp();
}
#Test
public void sendToSearchResultActivity()
{
onView(withId(R.id.etSearchName))
.perform(typeText("ssasa"), pressKey(KeyEvent.KEYCODE_SEARCH));
GlobalClass globalVariable = (GlobalClass) mActivityRule.getActivity().getApplicationContext();
globalVariable.setSearchStr("ssasa");
mActivityRule.getActivity().callForNextSearchActivity();
}
}
Additional Functional
#Override
public void callForNextSearchActivity() {
Intent intent = new Intent(getBaseContext(), SearchResultsActivity.class);
final GlobalClass globalVariable = (GlobalClass) getApplicationContext();
globalVariable.setSearchStr(getSearchStringFromSearchEditText());
startActivity(intent);
overridePendingTransition(R.anim.pull_in_right, R.anim.push_out_left);
}
Is it possible to have multi activity layer in Espresso testing?
If Yes .. How?
Yes, it is possible. In one of the samples they have demoed this.
https://code.google.com/p/android-test-kit/source/browse/testapp_test/src/main/java/com/google/android/apps/common/testing/ui/testapp/BasicTest.java#52][1]
public void testTypingAndPressBack() {
// Close soft keyboard after type to avoid issues on devices with soft keyboard.
onView(withId(R.id.sendtext_simple))
.perform(typeText("Have a cup of Espresso."), closeSoftKeyboard());
onView(withId(R.id.send_simple))
.perform(click());
// Clicking launches a new activity that shows the text entered above. You don't need to do
// anything special to handle the activity transitions. Espresso takes care of waiting for the
// new activity to be resumed and its view hierarchy to be laid out.
onView(withId(R.id.display_data))
.check(matches(withText(("Have a cup of Espresso."))));
// Going back to the previous activity - lets make sure our text was perserved.
pressBack();
onView(withId(R.id.sendtext_simple))
.check(matches(withText(containsString("Espresso"))));
}
Read the inline comment.
During the normal course of development, I noticed that a particular activity appears to have stopped responding the second time it is called.
i.e. menu->(intent)->activity->(back button)->menu->(intent)
There is nothing relevant in logcat.
I don't even know where to start debugging this nor what code to show so here are the onClick and onResume fragments:
if (!dictionary.getClassName().equals("")) {
this.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent i;
i = new Intent(mContext, NVGlobeNavigatorVC.class);
i.putExtra("PAGE_TITLE", title);
i.putExtra("TITLE", _dictionary._title);
mContext.startActivity(i);
});
} else {
findViewById(R.id.greaterthan).setVisibility(View.GONE);
}
and in the Activity being launched:
#Override
protected void onResume() {
super.onResume();
...
Nothing unusual in manifest either:
<activity
android:name=".NVViews.NVGlobeNavigatorVC"
android:theme="#style/WindowTitleBackground"
android:label="GlobeNavigator"/>
For clarity, I put breakpoints on mContext.startActivity(i) and super.onResume(). I click the view with the onClickListener and both breakpoints are hit as expected. I then press the back button which returns me to the menu. onPause() is called as expected.
I touch the view to launch the activity again, and the breakpoint on startActivity is hit but not in onResume() in the target activity. The screen goes black and the only way I can get going again is to restart the app. If I pause the debugger, it pauses in dalvik.system.NativeStart() which implies that the activity is never relaunched.
I don't think it's relevant, but I'm using Intellij IDEA and have deleted all of the output directories, invalidated the caches and done a full rebuild.
Target API is 8. I've tested on 2.3 and 4.0.4.
Any ideas? I'm stumped.
[EDIT]
In onPause, I save some stuff to prefs. The purpose of onResume() is to get them back again:
#Override
protected void onPause() {
super.onPause();
SCPrefs.setGlobeViewViewPoint(globeView.getViewPoint());
SCPrefs.setGlobeViewZoom(globeView.getZoom());
SCPrefs.setGlobeViewScale(globeView.getScale());
}
This code:
i = new Intent(mContext, NVGlobeNavigatorVC.class);
creates a new intent. The intent is of class NVGlobeNavigatorVC.class.
If you call it once, you create a new activity, lets call it "iTheFirst". If you back out of the activity, it executes "on pause". When you run the above code again, you create another new activity of the same class, but a different acitivity. Hence it won't resume your other activity, but make a new one that we could call "iTheSecond". It looks just like iTheFirst but is unique.
If you want to resume the above, after backing out of it, you need to keep a reference to it in your menu. Then in your onClick, look to see if that activity exists, and if not, make a new one and start it, and if it does exist, just resume it.
Here is a sample activity that remembers and restarts an activity:
Intent savedCueCardActivity = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState, R.layout.landing);
}
public void goToNextScreen(View v) {
if (savedCueCardActivity == null) {
savedCueCardActivity = new Intent().setClass(this, CueCardActivity.class);
startActivity(savedCueCardActivity);
// lastActivity.finish();
} else {
savedCueCardActivity.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(savedCueCardActivity);
}
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
}
I found the problem, and it's a bit esoteric.
I have a large static data structure which is loaded in a class static initialiser. There was a bug in that initialiser causing an infinite loop the second time it was called if the data structure was still loaded.
Because that class is referenced in my Activity, the class loader is loading it before onCreate() or onResume() is called.
The loop gave the appearance that the Activity loader had hung.
I managed to write two test cases in my XXTest.java with robotium-solo-3.2.1.jar included, luckily in JUnit view it shows the first one is done, which the device exactly worked (on emulator too).
Then it proceed to the second one, but it just hanging there forever! sorry I can't attach screen shot with my account.
here are my code:
public class XXTest extends ActivityInstrumentationTestCase2<SignInActivity> {
private Solo solo;
private Activity mActivity;
private static final String account = "someone";
private static final String pwd = "123456";
#SuppressWarnings("deprecation")
public XXTest() {
super("com.acompany.android", SignInActivity.class);
}
protected void setUp() throws Exception {
super.setUp();
this.mActivity = getActivity();
solo = new Solo(getInstrumentation(), mActivity);
}
#Smoke
public void testLogIn() throws Exception {
EditText accountInput = (EditText) solo.getView(R.id.edit_account);
EditText pwdInput = (EditText) solo.getView(R.id.edit_password);
solo.clearEditText(accountInput);
solo.clearEditText(pwdInput);
solo.enterText(accountInput, account);
solo.enterText(pwdInput, pwd);
solo.clickOnButton(mActivity.getResources()
.getString(R.string.text_sign_in));
solo.waitForActivity("MainActivity");
solo.assertCurrentActivity("Expect MainActivity shown...", "MainActivity");
boolean expected = true;
boolean actual = solo.searchButton(mActivity.getResources().getString(
R.string.welcome_dialog_start));
assertEquals("find friend dialog not shown", expected, actual);
}
#Smoke
public void testOpenPref() throws Exception {
solo.goBack();
solo.clickOnMenuItem(mActivity.getResources().getString(
R.string.text_preferences));
solo.assertCurrentActivity("Expected PrefActivity..", "PrefActivity");
solo.goBackToActivity("MainActivity");
solo.assertCurrentActivity("Expected MainActivity..", "MainActivity");
}
protected void tearDown() throws Exception {
super.tearDown();
}
}
I've searched the sample of NotePadTest.java from Robotium tutorial, those 3 test cases in it are just work fine!
Please tell me where goes wrong?? Am I missing something somewhere? why the second test case not running?
btw. Can there be more than one class extends ActivityInstrumentationTestCase2 in a test project? curious!
You need to use solo.finishOpenedActivities() in your tearDown().
#Robert - this is the issue with Activity testing itself , not to robotium specific .
For the first test method:
the basic flow you is like below:
1>in the setUp() method load the main activity (say MainActivity) > do some ops in your testMethod1() - that results to land you in another activity ( say AnotherActivity) > and in tearDown() you kill the launched activity in setUp() method which is MainActivity
note: but AnotherActivity remains live
For the second test method:
the basic flow you is like below:
2>in the setUp() method try loading the main activity (say MainActivity) again ,although the previously launched AnotherActivity is not yet got killed, so it hangs there , It doesnt even enter the testMethod2() fr execution -
note: the eclipse graphical runner shows it hangs while the execution marker points to the testMethod2() , people thinks that it got stuck in testMethod2() - but the problem lies in setUp() for testMethod2() not in testMethod2() itself.
Solution:
1>Just keep a look on your cross activity navigation - at the end of each testMethod() use solo.goBack() to come back to the same main activity MainActivity from your current Activity ( you got landed in because of your actions)
results - at the end of testMethod1() only the main activity which was opened in setUP() remains. So it gets killed successfully .No Activity remains alive and for the testMethod2().The setUP() is able to load the MainActivity again without a hang - and testMethod2() gets executed .
hope it clarifies :)
I'm writing a test for an activity that have a few buttons,
each one of than starts a new Activity,
How can I know if the button is starting the correct activity?
This is what I have so far:
public class MainActivityTest extends ActivityUnitTestCase<MainActivity> {
private Intent mMainIntent;
public MainActivityTest() {
super(MainActivity.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
mMainIntent = new Intent(Intent.ACTION_MAIN);
}
#MediumTest
public void testButtonActivityA () {
MainActivity activity = startActivity(mMainIntent, null, null);
Button buttonActivityA = (Button) activity.findViewById(com.project.R.id.button_activity_a);
buttonVoice.performClick();
Intent i = getStartedActivityIntent();
assertNotNull(i);
assertTrue(isFinishCalled());
}
}
PS: the 'isFinishedCalled()' is failing, how can this be if I raise a new fullscreen Activity?
Thanks,
It's failing because finish() isn't called.
you have to finish an activity yourself, otherwise when you open a new one it comes up over the top on the 'stack' and the original activity has onPause called but is still 'alive'. finish() is an implicit call that you can code into your app to destroy an activity.
Please go read about the Android Activity Lifecycle
Then learn to call when you should call finish()
I have a beginners problem. Here is my situation:
I want to start a new activity from the main activity. The code to launch the new activity is found in a separate class file. I seem to be passing the wrong arguments and I am ending up in a nullpointerexception when trying to launch the new activity. The new activity launches fine when I place the code in the main activity class file, therefore the second activity and the manifest are fine. Here is a sample of my code:
In my main activity class where I instanciate the second class (THIS IS MY MAIN ACTIVITY. I OMITTED THE REST BECAUSE I DO NOT THINK IT IS RELATED TO THE PROBLEM):
Tester mytest = new Tester();
mytest.test(this);
In my second class file (THIS IS NOT AN ACTIVITY; IT IS A CLASS THAT IS INSTANTIATED IN THE ACTIVITY):
public class Tester extends Activity {
Intent myIntent;
public void test (Context context) {
myIntent = new Intent (Intent.ACTION_VIEW);
myIntent.setClass(context, newActivity.class);
thebutton.setOnClickListener(
new OnClickListener() {
public void onClick(View v) {
startActivity(myIntent);
}
}
):}
When I perform the click I receive a nullpointerexception at startactivity. Can anyone enlighten me on this please?I am sure that I am wrongly using the context.
Activities are started with Intents. Please read the Android Application Fundamentals first and try the Hello World app :)
I understood that you will use your separate Tester class at all cost ;) so I'm trying to adapt and help you out there.
First of all, don't let your class inherit from Activity. This won't help you, cause this calls will probably not have any valid context. Activity somehow implements the template pattern, providing you key method like onCreate(...), onPause(...) etc and is instantiated by the Android OS.
If you still want to use the class, you have to pass in the context. Probably you're aiming for some MVC/MVP pattern structure, anyway.
public class Tester {
private Context context;
public Tester(Context context){
this.context = context;
}
public void test () {
final Intent myIntent = new Intent(context, NewActivity.class);
//guess this comes from somewhere, hope through a findViewById method
thebutton.setOnClickListener(
new OnClickListener() {
public void onClick(View v) {
context.startActivity(myIntent);
}
}
)};
}
}
This would be a proposed solution from my side. A problem I still see here is on how you retrieve the button in that test() method. In order to have that work properly you have to retrieve it from some View class (with view.findViewByid(R.id.myButton)) or to create it dynamically and associate it with the view during the onCreate(...) of your Activity (probably using an Inflater).