Giter Site home page Giter Site logo

androidtestingtutorial's Introduction

AndroidTestingTutorial

Getting started with Espresso Unit Testing

Why Testing?

testing is the process of evaluation a software item to detect differences between given input and expected output.

Categories of Testing

  1. Black box testing
  2. White box testing
    etc... others can be found here

Black box testing

Tests are based on requirements and functionality.

White box testing

Tests are based on coverage of code statements, branches, paths, conditions.

TDD

Test-driven development (TDD) is a software development process that relies on the repetition of a very short development cycle: requirements are turned into very specific test cases, then the software is improved to pass the new tests, only.

Android Testing Tools

  1. Espresso by google team
  2. Roboletric
  3. Appium

Espresso

Mainly focused on UI and Thread idealization, which helps the unit tests to run without worring about api response state It checks the threads and waits for ui thread to be idealize which is dismiss progress bar or any event which shows that activity is performing some event.

Why Espresso

Other tools like Roboletric is also famous for testing android apps but it has it's own android jar which is our basic android kit classes. As google updates their support library often it's hard to keep in update for Roboletric. And to mock the android classes becomes hard with Roboletric. Check out link here Roboletric vs Espresso for more details.

Let's start with testing

Let's check how to write test so in Espresso we have

@Rule
public ActivityTestRule<LoginActivity> mActivityTestRule = new ActivityTestRule<>(LoginActivity.class, true);

Above test rule defines for which activity you'r going to write test class
Now new ActivityTestRule<>(LoginActivity.class, true); if you do want to open activity which is not launcher activity then pass true in constructor else pass nothing for second parameter new ActivityTestRule<>(LoginActivity.class);
There is multiple ways to open activity so do checkout Espresso Doc.


@RunWith(AndroidJUnit4.class)
public class PerfomClickAndCheckTextError {
    
    @Rule
    public ActivityTestRule<LoginActivity> mActivityTestRule = new ActivityTestRule<>(LoginActivity.class, true);
    .......
}

You need to define that your going to use junit4 test class to run with below test class. if your test case is large then mention @LargeTest above class

Now before going any further with real test code other things to mention here is if we want to run some method before activity launches you can do it by specifying @Before annotation above your method.


    @RunWith(AndroidJUnit4.class)
    public class PerfomClickAndCheckTextError {
    
        @Rule
        public ActivityTestRule<LoginActivity> mActivityTestRule = new ActivityTestRule<>(LoginActivity.class, true);
    
        //To get resources in testing
        Resources resources;
        
        @Before
        public void initThingsHere() {
            //do stuff like database or preference or image copying here
            resources = InstrumentationRegistry.getTargetContext().getResources();
        }
    }

Like above I had taken resources.

Tutorial 1

We have started programming with hello world! program and for testing we will do the same. Simple step check the text is on the screen. but before that let's check how to find view from the screen in Espresso

To check there is 2 steps:

  1. Find view on screen
  2. Check if exists or displayed

Find view on screen


As we have findViewById in android, so in background what android system will do is it will check for that id view from rootview and give it back, we have onView() but to find views we can use multiple methods not by just ids. we have withId(), withText(), withTagKey() etc.

Check if exists or displayed


To check we have check() method in which we will give matcher which will conditionalize the view like if it displayed or not.

So we have

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

above code checked that screen has some textview having text Hello Floks!



Tutorial 2

Now that we have successed in finding view and performing checks we will move to step 2 which is perform events like typing and clicking. to click

    onView(withText("Login")).perform(click());


Tutorial 3

Merge click and checks in one

    onView(withId(R.id.btnLoginButton)).perform(click());
    onView(withId(R.id.edUsername)).check(matches(hasErrorText(resources.getString(R.string.msg_enter_valid_email))));



Tutorial 4

open activity with data in bundle as it's important to pass data with activity

you want to check activity with custom data so before writing test if

    @RunWith(AndroidJUnit4.class)
    public class PassDataInActivityTest {
    
        @Rule
        public ActivityTestRule<LoginActivity> mActivityTestRule = new ActivityTestRule<LoginActivity>(LoginActivity.class, true) {
            @Override
            protected Intent getActivityIntent() {
                Log.d(PassDataInActivityTest.class.getCanonicalName(), "getActivityIntent() called");
                Context targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
                Intent intent = new Intent(targetContext, LoginActivity.class);
                intent.putExtra("testingcheck", true);
                return intent;
            }
        };
    
    
        @Before
        public void initThingsHere() {
            //do stuff like database or preference or image copying here
        }
    
        @Test
        public void checkBlankEmailError() {
            //to check view on screen
            Bundle bundle = mActivityTestRule.getActivity().getIntent().getExtras();
            assertThat(bundle.getBoolean("testingcheck"), is(true));
            System.out.println("testingcheck:" + bundle.getBoolean("testingcheck"));
        }
    }

Tutorial 5

Responding to external intents like gallery picks It's hard to control external apps as with device applications can have different views so it's not steady like your UI. in this condition what you can do is develop dependency injected code where you can mock the intents results or you can give result of intents in testing. We are trying to archive this:

Let's check without DI(Dependency Injection)

For this you need to have espresso intents dependency in build.gradle file

    androidTestCompile ('com.android.support.test.espresso:espresso-intents:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })

excludes are important to exclude support libraries inside the espresso and use libs what you have included.

Now after dependency added we can move on to the main course which is to mock the intent results.

2 things to keep in mind is intending and intended

  1. Intending It is used for specifying Espresso that when unit test wants to open this type of intent please respond with intended result which i'm giving you to give.

2. Intended It is used to check if the event intended to open some activity or package? we can check that thing by this.
    Intent resultData = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    resultData.setData(Uri.parse(("content://media/external/images/media/162")));
    Matcher<Intent> MediaPickIntent = allOf(hasAction(Intent.ACTION_PICK), hasData(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI));
    Intents.init();
    intending(MediaPickIntent).respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, resultData));

In above example we have action pick event matcher which gives espresso hint that i'm finding this intent and by initlizing the intent we are starting intent checks for every intents. while intending tells that when I intend to do respond with the intent i'm giving. Output:

Tutorial 6

Espresso works like charm for views with view hierarchy but it's difficult to find if view is not bound by viewgroup like google map.

It's hard to find marker in map as it's part of google map but not actual viewgroup so to perform the click event on google map marker what we can do here is Use UiAutomator.

UiAutomator is a library which uses accessiblity nodes to determine the views and performs assertions or actions upon that.

add UiAutomator in build.gradle


    androidTestCompile("com.android.support.test.uiautomator:uiautomator-v18:2.1.1", {
        exclude group: "com.android.support", module: "support-annotations"
    })

After adding in build.gradle your ready to go We will create map activity for testing this feature. now to use UiAutomator we need to start with finding UIDevice.

    UiDevice mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

and to find the marker we need to find marker view or in UiAutomator world it is UiSelector.

    UiObject marker = mDevice.findObject(new UiSelector().descriptionContains("Marker in Sydney"));

in above we are finding the view or object which has "Marker in sydney" as their description. and our marker had one. once we found the object we can perform click operation.

this is easy to find marker as it is bound to node but info window has been drawn to canvas so it can not be clicked and i had used a trick to click on info window. basically info window is drawn above marker icon and so i already got marker object so i had taken marker bounds and performed click on it.

        try {
            marker.click();
            marker.clickTopLeft();
            Rect rects = marker.getBounds();
            mDevice.click(rects.centerX(), rects.top - 30);
        } catch (UiObjectNotFoundException e) {
            e.printStackTrace();
        }

If you do like the Tutorials please rate this repo and do share your own testing class or methodology. output:

Your browser does not support HTML5 video.

androidtestingtutorial's People

Contributors

parthdave93 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.