Skip to content

Instantly share code, notes, and snippets.

@mfdeveloper
Created August 21, 2019 20:26
Show Gist options
  • Select an option

  • Save mfdeveloper/289c6668da49cefa4d60dfc469d20a5f to your computer and use it in GitHub Desktop.

Select an option

Save mfdeveloper/289c6668da49cefa4d60dfc469d20a5f to your computer and use it in GitHub Desktop.
This is a git snippets to configure your Android project to run UI Tests without animations, using Cappuccino library

Android test - Infra e primeiro teste de interface

Adicionada infraestrutura para teste de instrumentação (teste de UI) utilizando o framework Espresso em conjunto com o projeto open source Cappucino para desativar animações do emulador/dispositivo.

As seguintes mudanças foram feitas para permitir a execução dos testes:

  • Modificações nos scripts gradle com permissões e tasks para desativar a animação dos dispositivos que irão executar os testes (emuladores ou smartphones conectados via USB)

  • Criada classe pai BehaviorTest, onde cada teste deve implementá-la passando a Activity a ser testada. Algo como:

  class MyBehaviorTest extends BehaviorTest<MyActivity> {

    @Test
     public void myCustomTest() {
         onView(...) // See Espresso documentation
     }
}

Adicionada também primeira classe de teste chamada DashboardBehaviorTest para DashboardActivity, contendo testes simples de cada elemento de sua interface.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="br.gov.fazenda.receita.pessoafisica"
android:installLocation="auto">
<!-- Disable animations on debug builds so that the animations do not interfere with Espresso
tests. Adding this permission to the manifest is not sufficient - you must also grant the
permission over adb! -->
<uses-permission android:name="android.permission.SET_ANIMATION_SCALE" />
</manifest>
package br.gov.fazenda.receita.pessoafisica;
import android.app.Activity;
import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.intent.Intents;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import com.metova.cappuccino.Cappuccino;
import com.metova.cappuccino.animations.SystemAnimations;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.runner.RunWith;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* Base instrumentation/UI test class
*
* All classes that have a @Test annotated method
* to run on emulator or device needs be inherit
* from this class
*
* @author Serpro 19/08/2016
* @see Cappuccino Uses this library internally to disable/enable animations on each test
*/
@RunWith(AndroidJUnit4.class)
public class BehaviorTest<T extends Activity> {
/**
* Stores the generic class reference.
* Needs this to pass to {@code ActivityTestRule} constructor
*
* @see ActivityTestRule
*/
protected Class<?> mGenericClass;
@Rule
public ActivityTestRule<T> mActivityRule;
public BehaviorTest(){
getGenericClass();
mActivityRule = new ActivityTestRule<>((Class<T>) mGenericClass, true, false);
}
@BeforeClass
public static void disableAnimations(){
SystemAnimations.disableAll(InstrumentationRegistry.getContext());
}
@AfterClass
public static void enableAnimations(){
SystemAnimations.enableAll(InstrumentationRegistry.getContext());
}
@Before
public void setUp() throws Exception {
// Prevents the 'NullPointerException' when call intended()
Intents.init();
mActivityRule.launchActivity(new Intent());
}
@After
public void tearDown() throws Exception {
Cappuccino.reset();
}
/**
* Set the class reference of the generic class passed to <T>,
* using Reflection Java API
*
* @see mGenericClass Store generic class reference in this property
* @return Class<?> Class reference of the generic class
*/
protected Class<?> getGenericClass(){
if(mGenericClass == null){
Type mySuperclass = getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
String className = tType.toString().split(" ")[1];
try {
mGenericClass = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return mGenericClass;
}
}
/**
* @see Reference to a Cappuccino library: https://github.com/autonomousapps/Cappuccino
*/
buildscript {
dependencies {
classpath "gradle.plugin.com.metova:cappuccino-plugin:0.7.3"
}
}
apply plugin: "com.metova.cappuccino-animations"
repositories {
// Either repository will work
mavenCentral()
jcenter()
}
task grantAnimationPermission(type: Exec, dependsOn: 'installDevDebug') { // or install{productFlavour}{buildType}
group = 'test'
description = 'Grant animation permission. Use this with on AndroidManifest.xml'
// or use $android.productFlavors.dev.applicationId
println 'Granting turnoff animation scale'
commandLine "adb shell pm grant $android.defaultConfig.applicationId android.permission.SET_ANIMATION_SCALE".split(' ')
}
tasks.whenTaskAdded { task ->
if (task.name.startsWith('assembleDebugAndroidTest')) {
task.dependsOn grantAnimationPermission
}
}
dependencies {
// ...other dependencies...
debugImplementation ('com.metova:cappuccino:0.8.1') {
transitive = false
}
releaseImplementation 'com.metova:cappuccino-no-op:0.8.1'
}
package br.gov.fazenda.receita.pessoafisica;
import android.content.ComponentName;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import br.gov.fazenda.receita.pessoafisica.ui.activity.AvaliacaoActivity;
import br.gov.fazenda.receita.pessoafisica.ui.activity.CalculoImpostoActivity;
import br.gov.fazenda.receita.pessoafisica.ui.activity.DashboardActivity;
import br.gov.fazenda.receita.pessoafisica.ui.activity.HistoricoCPFActivity;
import br.gov.fazenda.receita.pessoafisica.ui.activity.HistoricoRestituicaoActivity;
import br.gov.fazenda.receita.pessoafisica.ui.activity.OrientacoesListaActivity;
import br.gov.fazenda.receita.pessoafisica.ui.activity.QuizActivity;
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;
import static android.support.test.espresso.action.ViewActions.typeText;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.intent.Intents.intended;
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
/**
* Run DashboardActivity tests.
* Used to test clicks on each dashboard icons
*
* <b>Obs:</b> Each UI test needs inherit from <code>BehaviorTest</code>
* class passing the Activity like generic type
*
* @author Serpro 19/08/2016
*/
public class DashboardBehaviorTest extends BehaviorTest<DashboardActivity> {
@Test
public void openAvaliation(){
onView(withId(R.id.dashboard_avaliacao))
.perform(click());
intended(hasComponent(new ComponentName(getTargetContext(), AvaliacaoActivity.class)));
onView(withId(R.id.cardList))
.check(matches(isDisplayed()));
}
@Test
public void openHistoryCpf(){
onView(withId(R.id.dashboard_cpf))
.perform(click());
intended(hasComponent(HistoricoCPFActivity.class.getName()));
onView(withId(R.id.linearlayout_cpfbar))
.check(matches(isDisplayed()));
}
@Test
public void openHistoryRestituation(){
onView(withId(R.id.dashboard_restituicao))
.perform(click());
intended(hasComponent(HistoricoRestituicaoActivity.class.getName()));
onView(withId(R.id.linearlayout_restituicaobar))
.check(matches(isDisplayed()));
}
@Test
public void openCalculateTribute(){
onView(withId(R.id.dashboard_calculo_imposto))
.perform(click());
intended(hasComponent(CalculoImpostoActivity.class.getName()));
onView(withId(R.id.fragment_calculo_mensal))
.check(matches(isDisplayed()));
}
@Test
public void openQuiz(){
onView(withId(R.id.dashboard_quiz))
.perform(click());
intended(hasComponent(QuizActivity.class.getName()));
onView(withId(R.id.quiz_fragment))
.check(matches(isDisplayed()));
}
@Test
public void openOrientations(){
onView(withId(R.id.dashboard_orientacoes))
.perform(click());
intended(hasComponent(OrientacoesListaActivity.class.getName()));
onView(withId(R.id.listview_orientacoes))
.check(matches(isCompletelyDisplayed()));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment