Writing tests for an android app that logs into Fa

2020-06-29 08:25发布

问题:

From this question/answer I got the idea to use UIAutomator to test my app that requires logging into Facebook.

Writing tests for an Android app that logs into Facebook

I tried

        UiObject2 editText = mDevice.findObject(By.clazz("android.widget.EditText"));
        editText.setText("test@email.com");

As well as other things but whatever I do I can't get it to fill out the field. I used hierachyviewer tool to see that it was an EditText. It's a webview, though, so I don't know.

Is this possible?

My full test code class is attached below:

package com.greenrobot.yesorno.test;

import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.View;

import com.greenrobot.yesorno.Home;
import com.greenrobot.yesorno.R;
import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;

import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import timber.log.Timber;

import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.hamcrest.Matchers.hasToString;
import static org.hamcrest.Matchers.startsWith;


/**
 * Created by andytriboletti on 1/15/16.
 */
@RunWith(AndroidJUnit4.class)
@LargeTest
public class TestLogin  {

    private UiDevice mDevice;

    private static final String PACKAGE_NAME = "com.greenrobot.yesorno";
    private static final int LAUNCH_TIMEOUT = 5000;

    @Rule
    public ActivityTestRule<Home> mActivityRule = new ActivityTestRule(Home.class);

    public TestLogin() {
        super();
    }

    @Before
    public void initTest() {
        // Initialize UiDevice instance
    
        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

//
//        // Start from the home screen
//        mDevice.pressHome();
//
//        // Wait for launcher
    
//        String launcherPackage = mDevice.getCurrentPackageName();
//        mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT);
//
//        // Launch the app
    
//        Context context = InstrumentationRegistry.getContext();
//        Intent intent = context.getPackageManager().getLaunchIntentForPackage(PACKAGE_NAME);
//
//        // Clear out any previous instances
    
//        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
//        context.startActivity(intent);
//
//        // Wait for the app to appear
    
//        mDevice.wait(Until.hasObject(By.pkg(PACKAGE_NAME).depth(0)), LAUNCH_TIMEOUT);
    }

    public void fillInEmail() {
        onView(withId(R.id.authButton)).perform(click());


            //new UiObject(new UiSelector().description("Email or Phone")).setText("test@email.com");
            //new UiObject(new UiSelector().
           // boolean result = new UiObject(new UiSelector().className(android.widget.EditText.class.getName())).setText("test@email.com");
            //Timber.d(result.getText());
            //UiObject2 editText = new UiObject2(new UiSelector(). className("android.widget.EditText").instance(0));
            //UiObject editText = new UiObject(new UiSelector().text("Email or Phone"));
            UiObject2 editText = mDevice.findObject(By.clazz("android.widget.EditText"));
            editText.setText("test@email.com");
            SystemClock.sleep(5000);


    }
    @Test
    public void testLogin() {
        try {
            onView(withId(R.id.welcome)).check(matches(isDisplayed()));
            Timber.d("Logged out");
            //fillInEmail();
        }
        catch(NoMatchingViewException e) {

            onView(withId(R.id.name_age)).check(matches(isDisplayed()));
            Timber.d("Not logged out");
            onView(withId(R.id.slidingmenumain)).perform(actionOpenDrawer());
            //SystemClock.sleep(5000);
            onData(hasToString(startsWith("Logout")))
                    .inAdapterView(withId(android.R.id.list))
                    .perform(click());

            //fillInEmail();

            //openDrawer(R.id.drawer_layout);
            //Espresso.onView(Matchers.allOf(ViewMatchers.withId(R.id.drawerItemNameTextView), ViewMatchers.hasSibling(ViewMatchers.withText(((NavDrawerItem)item).getItemName())))).perform(ViewActions.click());


        }

//        onView(withText("Hello world!")).check(matches(isDisplayed()));

        //onView(withId(R.id.changeTextBt)).perform(click());

    }


    private static ViewAction actionOpenDrawer() {
        return new ViewAction() {
            @Override
            public Matcher<View> getConstraints() {
                return isAssignableFrom(SlidingMenu.class);
            }

            @Override
            public String getDescription() {
                return "open drawer";
            }

            @Override
            public void perform(UiController uiController, View view) {
                ((SlidingMenu) view).showMenu();
            }
        };
    }
    private static ViewAction actionCloseDrawer() {
        return new ViewAction() {
            @Override
            public Matcher<View> getConstraints() {
                return isAssignableFrom(SlidingMenu.class);
            }

            @Override
            public String getDescription() {
                return "close drawer";
            }

            @Override
            public void perform(UiController uiController, View view) {
                //((SlidingMenu) view).close(GravityCompat.START);
            }
        };
    }
}

Edit: I actually used uiautomatorviewer not hierachyviewer. Here's a screenshot showing it's an edit text. At least according to this tool.

回答1:

I didn't try this against a Facebook login page, but I was able to do this on a different page I created.

I was able to use both UIObject and UIObject2 to location an input box in a web form using the EditText class. I was able to both to set the text in the input box using setText(), but I was not able to read it out with getText().

Selecting HTML input forms requires some care. The only way you can reliably select a specific input is by using instance() to find the n'th indexed field. This means you should probably be limiting the scope of your searches to the WebView parent object (otherwise some other EditText on the screen might offset everything).

Another thing you need to look out for is the load time of the WebView. It's not going to happen instantaneously, so you will need to wait some reasonable amount of time to let the page load.

Here is a bit of sample code that let me find the second input box on a HTML page and put text into it:

UiObject input = mDevice.findObject(new UiSelector()
    .instance(1)
    .className(EditText.class));
input.setText("text");