Transcripted Summary

After completing our page object classes it is time to refactor our test cases. To start, let’s open the class "OrderItemFromMenuTheTest" and refactor the shouldBeAbleToSelectAnItemInTheMenu() test method with our page objects.

Start by initializing new page object instances in the "OrderItemFromMenuTheTest" class.


public class OrderItemFromMenuTheTest extends TestBase {
    OnboardingScreen onboardingScreen = new OnboardingScreen();
    MenuScreen menuScreen = new MenuScreen();
    .
    .
    .
}

Inside of the shouldBeAbleToSelectAnItemInTheMenu() test method, the calls to "close_button" and "use_menu" need to be refactored.

Recall that the method scrollToMenuItem() we defined in the previous chapter requires two arguments.

So this:


    public void shouldBeAbleToSelectAnItemInTheMenu() {
        onView(ViewMatchers.withId(R.id.close_button))
            .perform(click());

        onView(withId(R.id.use_menu))
            .perform(click());

        onView(withId(R.id.beverage_recycler_view))
            .perform(actionOnItem(hasDescendant(withText("CAPPUCCINO"))
                , click()));

        onView(withId(R.id.beverage_detail_title))
            .check(matches(withText("Cappuccino")));
    }

Becomes:


    public void shouldBeAbleToSelectAnItemInTheMenu() {
        onboardingScreen.closeOnBoardingScreen();

        menuScreen.clickMenuButton();
        menuScreen
            .scrollToMenuItem("CAPPUCCINO", "Cappuccino");
    }

Let’s also go ahead and add private access modifiers to our variables.

Now we can run our test and check the results of our refactored code.



Our test passes and appears to be working.

Now we should remove all of the unused method import statements resulting from our changes.

From the "Code" toolbar, select "Optimize Imports".



Now our test code is clean.

Let's refactor the second test. Open the "CreateCustomOderWithIngredientsTest" class.

Here, we find all of the steps previously refactored for the page object pattern.

The "Close" button is from the onboarding screen, the "+" and "Chocolate" elements are from the custom order screen, and the order summary is from the review order screen.

So we have three page objects.

As in the previous example, begin by initializing new page object instances in class "CreateCustomOderWithIngredientsTest":


public class CreateCustomOderWithIngredientsTest extends TestBase {
    OnboardingScreen onboardingScreen = new OnboardingScreen();
    CustomOrderScreen customOrderScreen = new CustomOrderScreen();
    ReviewOrder reviewOrder = new ReviewOrder();
   .
   .
   .
}

Now refactor the test using page objects. Method customOrderScreen.customizeYourOrder() takes an argument for the number of shots.

So this:


    public void orderOverViewShouldDisplayIngredients() {
        onView(ViewMatchers.withId(R.id.close_button))
            .perform(click());

        onView(withText("+"))
            .perform(click(), click());
        onView(withId(R.id.chocolate))
            .perform(click());
        onView(withText("Review order"))
            .perform(click());

        onView(withId(R.id.beverage_detail_ingredients))
            .check(matches(
                withText("Ingredients:\n2 shots of espresso\nChocolate")));
    }

Becomes:


    public void orderOverViewShouldDisplayIngredients() {
        onboardingScreen.closeOnBoardingScreen();
        customOrderScreen.customizeYourOrder(4);
        reviewObject.checkIngredients(3);
    }

Recall that the test procedure subtracts one shot after adding shots so our final ingredient count should be 3.

Let’s run this test and check the test result.



The ingredient count appears to be correct and our test passes.

The last class we need to refactor is "SendOrderToEmailTest". Here we will open the class and paste the same three page object instantiations we used in the previous test.


public class SendOrderToEmailTest extends TestBase {
    OnboardingScreen onboardingScreen = new OnboardingScreen();
    CustomOrderScreen customOrderScreen = new CustomOrderScreen();
    ReviewOrder reviewOrder = new ReviewOrder();
   .
   .
   .
}

Now refactor the shouldSendAnIntentContainingTheRightOrderDetails() method.

Method customizeYourOrder() requires an item count parameter and reviewOrder() needs the appropriate text parameters.

So this:


    public void shouldSendAnIntentContainingTheRightOrderDetails() {
        onView(ViewMatchers.withId(R.id.close_button))
            .perform(click());

        for (int i = 0; i < 4; i++) {
            onView(withText("+")).perform(click());
        }
        onView(withText("-"))
            .perform(click());
        onView(withId(R.id.chocolate))
            .perform(click());
        onView(withText("Review order"))
            .perform(click());

        onView(withId(R.id.name_text_box))
            .perform(scrollTo(), typeText("Moataz"));
        onView(withId(R.id.custom_order_name_box))
            .perform(scrollTo(), typeText("TAU Order Name"));
        onView(withId(R.id.mail_order_button))
            .perform(scrollTo(), click());

        intended(allOf(
            hasAction(equalTo(Intent.ACTION_SENDTO)),
            hasExtra(Intent.EXTRA_SUBJECT, "Order: Moataz - TAU Order Name")));
    }

Becomes:


    public void shouldSendAnIntentContainingTheRightOrderDetails()
    {
        onboardingScreen.closeOnBoardingScreen();
        customOrderScreen.customizeYourOrder(4);
        reviewOrder.reviewOrder("Moataz", "TAU Order Name");
    }

Note that we no longer need the third parameter of reviewOrder() since we already include that information as part of the order title.

Let’s remove that last parameter from the method definition in "ReviewOrder.java".

Now run our test and check the test result.



The test passes.


# Running Multiple Test Cases using Test Suite (Demo)

In this demo we will learn how to run multiple test cases using a test suite.

After finishing the implementation of the page object and refactoring our test cases it is time to create a custom class to run all of the test cases together.

Right-click on the "java" folder and select "New > Package".



Call this new package "runner". Now right-click on the new "runner" folder and select "New > Java Class".



Name this class "UITestSuite".

In the generated class add a @RunsWith annotation with the argument "Suite.class" from JUnitRunner.


@RunWith(Suite.class)
public class UITestSuite {

}

Also add annotation @Suite.SuiteClasses() into which we will pass the classes that we wish to run.


@RunWith(Suite.class)
@Suite.SuiteClasses(
    {CreateCustomOderWithIngredientsTest.class,
        OrderItemFromMenuTheTest.class,
        SendOrderToEmailTest.class
    })

public class UITestSuite {

}

Now we can run this suite and check the results.

On execution it will begin to run all of the test cases added in the annotations. All of the test cases appear to pass.


# Creating Custom Annotations (Demo)

In this demo we will learn how to create custom annotations for our test cases.

For example, we can create an annotation for a smoke test or an annotation for an end-to-end test.

Custom annotations offer additional naming flexibility for organizational purposes.

We will create two custom annotations, one for smoke tests and one for end-to-end tests.

Afterwards we will use them in our test cases.

Right-click on the "java" folder and select "New > Package".



Call this new package "utils" and click "OK".

Now we need to create two interfaces, one for end-to-end tests and one for smoke tests.

Right-click on the "utils" package and select "New > Java Class".



Call this class "E2ETest" and change the "Kind:" field from "Class" to "Interface".

Click "OK".

Repeat these steps to create a second interface named "SmokeTest".

To complete the implementation we need to add two lines of annotations to each class as well as prefixing "interface" with an "@" symbol which effectively makes it a runtime policy.


@Target( {ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface E2ETest {

}


@Target( {ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SmokeTest {

}

To use these annotations in our tests simply reference one or the other below the @Test annotation. For example:


@Test
public void orderOverViewShouldDisplayIngredients() {

}

Becomes:


@Test
@SmokeTest //alternately @E2ETest
public void orderOverViewShouldDisplayIngredients() {

}

There are other built-in annotations provided by Android and JUnit. These include:

  • @SmallTest (androidx.test.filters)

  • @LargeTest (androidx.test.filters)

  • @MediumTest (androidx.test.filters)

If you only wish to run end-to-end tests or only smoke tests, we can specify an annotation in the "build.gradle" file and pass the environmental variable with that specification.

In the next chapter we will explore annotation usage with Cucumber.


CreateCustomOderWithIngredientsTest

 package tests;

import androidx.test.filters.SmallTest;
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;

import org.junit.Test;
import org.junit.runner.RunWith;

import pageobjects.CustomOrderScreen;
import pageobjects.OnboardingScreen;
import pageobjects.ReviewOrderScreen;

@RunWith(AndroidJUnit4ClassRunner.class)
@SmallTest
public class CreateCustomOderWithIngredientsTest extends TestBase {

    private OnboardingScreen onboardObject = new OnboardingScreen();
    private CustomOrderScreen customizeObject = new CustomOrderScreen();
    private ReviewOrderScreen reviewObject = new ReviewOrderScreen();

    @Test
    @SmokeTest
    public void orderOverViewDisplayIngredients() {
        onboardObject.closeOnBoardingScreen();
        customizeObject.customizeYourOrder(3);
        reviewObject.checkIngredients(2);
    }
}

# OrderItemFromMenuTheTest

package tests;

import androidx.test.filters.MediumTest;
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;

import org.junit.Test;
import org.junit.runner.RunWith;

import pageobjects.MenuScreen;
import pageobjects.OnboardingScreen;

@RunWith(AndroidJUnit4ClassRunner.class)
@MediumTest
public class OrderItemFromMenuTheTest extends TestBase {

    private OnboardingScreen onboardObject = new OnboardingScreen();
    private MenuScreen menuObject = new MenuScreen();
    private String selectedItem = "CAPPUCCINO";
    private String itemTitle = "Cappuccino";

    @Test
    @E2ETest
    public void selectAnItemInTheMenuWithPageObject() {
        onboardObject.closeOnBoardingScreen();
        menuObject.clickOnMenuButton();
        menuObject.scrollToMenuItem(selectedItem, itemTitle);
    }
}

# SendOrderToEmailTest

package tests;

import androidx.test.filters.LargeTest;
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;

import org.junit.Test;
import org.junit.runner.RunWith;

import pageobjects.CustomOrderScreen;
import pageobjects.OnboardingScreen;
import pageobjects.ReviewOrderScreen;

@RunWith(AndroidJUnit4ClassRunner.class)
@LargeTest
public class SendOrderToEmailTest extends TestBase {

    private OnboardingScreen onboardObject = new OnboardingScreen();
    private CustomOrderScreen customizeObject = new CustomOrderScreen();
    private ReviewOrderScreen reviewObject = new ReviewOrderScreen();

    private String name = "Moataz";
    private String orderName = "TAU Order Name";
    private String mailSubject = "Order: Moataz - TAU Order Name";


    @Test
    public void sendAnIntentContainingTheRightOrderDetails() {
        onboardObject.closeOnBoardingScreen();
        customizeObject.customizeYourOrder(4);
        reviewObject.reviewOrder(name, orderName, mailSubject);
    }
}

# TestBase

package tests;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;

import androidx.test.espresso.intent.rule.IntentsTestRule;
import androidx.test.platform.app.InstrumentationRegistry;

import org.junit.Rule;

import nl.testchamber.mailordercoffeeshop.MainActivity;

class TestBase {

    @Rule
    public IntentsTestRule<MainActivity> activityTestRule =
            new IntentsTestRule<MainActivity>(MainActivity.class) {
                @Override
                public void beforeActivityLaunched() {
                    super.beforeActivityLaunched();
                    Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
                    SharedPreferences.Editor editor =
                            context.getSharedPreferences(context.getPackageName(),
                                    Activity.MODE_PRIVATE).edit();
                    editor.putBoolean("is_first_launch", true);
                    editor.commit();
                }
            };
}

# InstrumentationTestSuite

package runner;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;

import tests.CreateCustomOderWithIngredientsTest;
import tests.OrderItemFromMenuTheTest;
import tests.SendOrderToEmailTest;

@RunWith(Suite.class)
@Suite.SuiteClasses(
    {CreateCustomOderWithIngredientsTest.class,
        OrderItemFromMenuTheTest.class,
        SendOrderToEmailTest.class
    })
public class InstrumentationTestSuite {}

# E2ETest

package utils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target( {ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface E2ETest {
}

# SmokeTest

package utils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target( {ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SmokeTest {
}



Resources



© 2021 Applitools. All rights reserved. Terms and Conditions Privacy Policy GDPR