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.
Related
So I've written a basic test for my homescreen right now that checks if the three buttons on the homescreen are clickable. I was wondering how I would check to see if each of the buttons go to the right activity when they are clicked.
#RunWith(AndroidJUnit4.class)
#SmallTest
public class HomeScreenTest {
#Rule
public ActivityTestRule<StartActivity> mActivityRule = new ActivityTestRule<>(StartActivity.class);
#Test
public void testButton() {
Espresso.onView(withId(R.id.event_button)).check(matches(isClickable()));
Espresso.onView(withId(R.id.navigation_button)).check(matches(isClickable()));
Espresso.onView(withId(R.id.alarm_button)).check(matches(isClickable()));
}
}
two options for you.
assert on the next activity component to see it is correctly showing. or,
You probably need to test the Intent that you are sending through button clicks.
see https://google.github.io/android-testing-support-library/docs/espresso/intents/
#Test
public void validateIntentSentToPackage() {
user.clickOnView(system.getView(R.id.callButton));
intended(toPackage("com.android.phone"));
}
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.
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 3 screens in my app, each of which are in their own classes. When the app launches, my Driver class sets up some GUI elements, and then launches the first Intent.
I have a separate GUI class (which Driver invokes) which handles everything from menu's to dialog boxes. Previously my app didn't use Intents so I could pass the activity/context from Driver to Gui in its constructor as an object of type Activity and as a result could define layouts etc like LinearLayout ll = new LinearLayout(activity) and everything would be operating in the same activity/context.
Since I've moved to using intents, each Activity/Class has its own context, thus the previous dialogs and popup boxes from the Gui class are in the background and not running. I get an error saying android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy#406629a0 is not valid; is your activity running? when I click on a button to launch a dialog.
To me, this indicates the new Intents have taken over the foreground and the objects from the previous context are out of scope.
So, is there a way I can still pass the same context through to the new Intents so I can still access these shared dialogs? Or will I have to bring the code into each class (duplicate code)?
In case thats a bit hard to understand, here is some basic source code:
public class Driver extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Gui display = new Gui(this);
display.showScreen();
}
}
/////////////GUI.java///////////////////////
public class Gui
{
private Activity activity;
private Gui()
{}
public Gui(Activity _activity)//,Context _context)
{
this();
activity = _activity;
}
public void showScreen()
{
if(isLocationMode())
{
Intent i = new Intent(activity,LocationScreen.class);
//i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(i);
//locatScreen = new LocationScreen(activity);
//mainLayout.addView(locatScreen.getView());
}
else if (isManageMode())
{
Intent i = new Intent(activity,ManageScreen.class);
//i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(i);
//manageScreen = new ManageScreen(activity);
//mainLayout.addView(manageScreen.getView());
}
else if (isForwardMode())
{
Intent i = new Intent(activity,ForwardScreen.class);
//i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(i);
//forwardScreen = new ForwardScreen(activity);
//mainLayout.addView(forwardScreen.getView());
}
}
}
Have a setContext(Activity _activity) method in your Gui and call this in the onCreate of each activity?
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).