Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Espresso, Beyond the basics

Iñaki Villar
October 23, 2016

Espresso, Beyond the basics

Iñaki Villar

October 23, 2016
Tweet

More Decks by Iñaki Villar

Other Decks in Technology

Transcript

  1. Instrumentation MonitorningInstrumentation AndroidJunitRunner class notClass size log annotation notAnnotation numShards

    shardIndex delay_msec coverage coverageFile suiteAssignment debug listener package notPackage timeout_msec testFile disableAnalytics appListener idle
  2. Instrumentation MonitorningInstrumentation AndroidJunitRunner class notClass size log annotation notAnnotation numShards

    shardIndex delay_msec coverage coverageFile suiteAssignment debug listener package notPackage timeout_msec testFile disableAnalytics appListener idle
  3. Instrumentation MonitorningInstrumentation AndroidJunitRunner class notClass size log annotation notAnnotation numShards

    shardIndex delay_msec coverage coverageFile suiteAssignment debug listener package notPackage timeout_msec testFile disableAnalytics appListener idle
  4. Instrumentation MonitorningInstrumentation AndroidJunitRunner class notClass size log annotation notAnnotation numShards

    shardIndex delay_msec coverage coverageFile suiteAssignment debug listener package notPackage timeout_msec testFile disableAnalytics appListener idle
  5. Instrumentation MonitorningInstrumentation AndroidJunitRunner class notClass size log annotation notAnnotation numShards

    shardIndex delay_msec coverage coverageFile suiteAssignment debug listener package notPackage timeout_msec testFile disableAnalytics appListener idle
  6. 
 perform(click());
 new GeneralClickAction(Tap.SINGLE, VISIBLE_CENTER, Press.FINGER)); 
 MotionEvents.sendDown(uiController, coordinates, precision);


    
 uiController.injectMotionEvent(motionEvent);
 
 MainActivityTest
 
 ViewActions
 
 Tapper
 
 MotionEvents

  7. @Override
 public void loopMainThreadUntilIdle() {
 do {
 EnumSet<IdleCondition> condChecks =

    EnumSet.noneOf(IdleCondition.class);
 if (!asyncTaskMonitor.isIdleNow()) {
 asyncTaskMonitor.notifyWhenIdle(…);
 condChecks.add(IdleCondition.ASYNC_TASKS_HAVE_IDLED);
 }
 
 if (!compatTaskMonitor.isIdleNow()) {
 compatTaskMonitor.notifyWhenIdle(…);
 condChecks.add(IdleCondition.COMPAT_TASKS_HAVE_IDLED);
 }
 
 if (!idlingResourceRegistry.allResourcesAreIdle()) {
 idlingResourceRegistry.notifyWhenAllResourcesAreIdle(…);
 condChecks.add(IdleCondition.DYNAMIC_TASKS_HAVE_IDLED);
 }
 
 loopUntil(condChecks);
 } while (!asyncTaskMonitor.isIdleNow() || !compatTaskMonitor.isIdleNow()()
 || !idlingResourceRegistry.allResourcesAreIdle());
 } UiControllerImpl.java
  8. @Override
 public void loopMainThreadUntilIdle() {
 do {
 EnumSet<IdleCondition> condChecks =

    EnumSet.noneOf(IdleCondition.class);
 if (!asyncTaskMonitor.isIdleNow()) {
 asyncTaskMonitor.notifyWhenIdle(…);
 condChecks.add(IdleCondition.ASYNC_TASKS_HAVE_IDLED);
 }
 
 if (!compatTaskMonitor.isIdleNow()) {
 compatTaskMonitor.notifyWhenIdle(…);
 condChecks.add(IdleCondition.COMPAT_TASKS_HAVE_IDLED);
 }
 
 if (!idlingResourceRegistry.allResourcesAreIdle()) {
 idlingResourceRegistry.notifyWhenAllResourcesAreIdle(…);
 condChecks.add(IdleCondition.DYNAMIC_TASKS_HAVE_IDLED);
 }
 
 loopUntil(condChecks);
 } while (!asyncTaskMonitor.isIdleNow() || !compatIdle()
 || !idlingResourceRegistry.allResourcesAreIdle());
 } UiControllerImpl.java
  9. @Override
 public void loopMainThreadUntilIdle() {
 do {
 EnumSet<IdleCondition> condChecks =

    EnumSet.noneOf(IdleCondition.class);
 if (!asyncTaskMonitor.isIdleNow()) {
 asyncTaskMonitor.notifyWhenIdle(…);
 condChecks.add(IdleCondition.ASYNC_TASKS_HAVE_IDLED);
 }
 
 if (!compatTaskMonitor.isIdleNow()) {
 compatTaskMonitor.notifyWhenIdle(…);
 condChecks.add(IdleCondition.COMPAT_TASKS_HAVE_IDLED);
 }
 
 if (!idlingResourceRegistry.allResourcesAreIdle()) {
 idlingResourceRegistry.notifyWhenAllResourcesAreIdle(…);
 condChecks.add(IdleCondition.DYNAMIC_TASKS_HAVE_IDLED);
 }
 
 loopUntil(condChecks);
 } while (!asyncTaskMonitor.isIdleNow() || !compatIdle()
 || !idlingResourceRegistry.allResourcesAreIdle());
 } UiControllerImpl.java
  10. private final AtomicReference<IdleMonitor> monitor = new AtomicReference<IdleMonitor>(null); private final ThreadPoolExecutor

    pool;
 private final AtomicInteger activeBarrierChecks = new AtomicInteger(0);
 AsyncTaskPoolMonitor.java
  11. boolean isIdleNow() {
 if (!pool.getQueue().isEmpty()) {
 return false;
 } else

    {
 int activeCount = pool.getActiveCount();
 if (0 != activeCount) {
 if (monitor.get() == null) {
 activeCount = activeCount - activeBarrierChecks.get();
 }
 }
 return 0 == activeCount;
 }
 } private final AtomicReference<IdleMonitor> monitor = new AtomicReference<IdleMonitor>(null); private final ThreadPoolExecutor pool;
 private final AtomicInteger activeBarrierChecks = new AtomicInteger(0);
 AsyncTaskPoolMonitor.java
  12. public boolean registerResources(final List<? extends IdlingResource> resourceList) { } public

    boolean unregisterResources(final List<? extends IdlingResource> resourceList) {
 }
 IdlingResourceRegistry.java
  13. boolean allResourcesAreIdle() {
 for (int i = idleState.nextSetBit(0); i >=

    0 && i < resources.size();
 i = idleState.nextSetBit(i + 1)) {
 idleState.set(i, resources.get(i).isIdleNow());
 }
 return idleState.cardinality() == resources.size();
 } public boolean registerResources(final List<? extends IdlingResource> resourceList) { } public boolean unregisterResources(final List<? extends IdlingResource> resourceList) {
 }
 IdlingResourceRegistry.java
  14. abstract class WrappingExecutorService implements ExecutorService {
 private final ExecutorService delegate;


    
 protected GuavaWrappingExecutorService(ExecutorService delegate) {
 this.delegate = checkNotNull(delegate);
 }
 
 protected abstract <T> Callable<T> wrapTask(Callable<T> callable);
 
 protected Runnable wrapTask(Runnable command) {
 final Callable<Object> wrapped = wrapTask(Executors.callable(command, null));
 return new Runnable() {
 @Override
 public void run() {
 try {
 wrapped.call();
 } catch (Exception e) {
 }
 }
 };
 }
 
 @Override
 public final void execute(Runnable command) {
 delegate.execute(wrapTask(command));
 }
 
 @Override
 public final <T> Future<T> submit(Callable<T> task) {
 return delegate.submit(wrapTask(checkNotNull(task)));
 }
 
 @Override
 public final <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
 throws InterruptedException {
 return delegate.invokeAll(wrapTasks(tasks));
 }
 }
 Guava
  15. public class IdlingResourceExecutorService extends GuavaWrappingExecutorService {
 
 private final CountingIdlingResource

    mIdlingResource;
 
 public IdlingResourceExecutorService(ExecutorService delegate,
 CountingIdlingResource idlingResource) {
 super(delegate);
 mIdlingResource = idlingResource;
 }
 
 @Override
 protected <T> Callable<T> wrapTask(Callable<T> callable) {
 return new WrappedCallable<>(callable);
 }
 
 private final class WrappedCallable<T> implements Callable<T> {
 private final Callable<T> delegate;
 
 
 public WrappedCallable(Callable<T> delegate) {
 this.delegate = delegate;
 }
 
 @Override
 public T call() throws Exception {
 mIdlingResource.increment();
 T call;
 try {
 call = delegate.call();
 } finally {
 mIdlingResource.decrement();
 }
 return call;
 }
 }
 }
  16. public class IdlingResourceExecutorService extends GuavaWrappingExecutorService {
 
 private final CountingIdlingResource

    mIdlingResource;
 
 public IdlingResourceExecutorService(ExecutorService delegate,
 CountingIdlingResource idlingResource) {
 super(delegate);
 mIdlingResource = idlingResource;
 }
 
 @Override
 protected <T> Callable<T> wrapTask(Callable<T> callable) {
 return new WrappedCallable<>(callable);
 }
 
 private final class WrappedCallable<T> implements Callable<T> {
 private final Callable<T> delegate;
 
 
 public WrappedCallable(Callable<T> delegate) {
 this.delegate = delegate;
 }
 
 @Override
 public T call() throws Exception {
 mIdlingResource.increment();
 T call;
 try {
 call = delegate.call();
 } finally {
 mIdlingResource.decrement();
 }
 return call;
 }
 }
 }
  17. public class IdlingResourceExecutorService extends GuavaWrappingExecutorService {
 
 private final CountingIdlingResource

    mIdlingResource;
 
 public IdlingResourceExecutorService(ExecutorService delegate,
 CountingIdlingResource idlingResource) {
 super(delegate);
 mIdlingResource = idlingResource;
 }
 
 @Override
 protected <T> Callable<T> wrapTask(Callable<T> callable) {
 return new WrappedCallable<>(callable);
 }
 
 private final class WrappedCallable<T> implements Callable<T> {
 private final Callable<T> delegate;
 
 
 public WrappedCallable(Callable<T> delegate) {
 this.delegate = delegate;
 }
 
 @Override
 public T call() throws Exception {
 mIdlingResource.increment();
 T call;
 try {
 call = delegate.call();
 } finally {
 mIdlingResource.decrement();
 }
 return call;
 }
 }
 }
  18. RxJava public class RxSchedulerHook extends RxJavaSchedulersHook {
 
 private Scheduler

    customScheduler;
 private CountingIdlingResource idling;
 private static RxSchedulerHook sInstance;
 public RxSchedulerHook(CountingIdlingResource countingIdlingResource) {
 FailedTest watcher = new FailedTest();
 idling = countingIdlingResource;
 customScheduler = new Scheduler() {
 @Override public Scheduler.Worker createWorker() {
 return new CustomWorker();
 }
 };
 }

  19. @Override public Subscription schedule(final Action0 action, final long delayTime, TimeUnit

    unit) {
 return super.schedule(new Action0() {
 @Override public void call() {
 
 action.call();
 }
 }, delayTime, unit);
 }
 
 @Override public Subscription schedule(final Action0 action) {
 return super.schedule(new Action0() {
 @Override public void call() {
 idling.increment();
 try {
 action.call();
 } finally {
 idling.decrement();
 }
 }
 });
 } RxJava
  20. @Before
 public void setUp() {
 OkHttpClient client = new OkHttpClient();


    IdlingResource resource = OkHttp3IdlingResource.create("OkHttp", client);
 Espresso.registerIdlingResources(resource);
 } OkHttp3IdlingResource
  21. @Before
 public void setUp() {
 OkHttpClient client = new OkHttpClient();


    IdlingResource resource = OkHttp3IdlingResource.create("OkHttp", client);
 Espresso.registerIdlingResources(resource);
 } private OkHttp3IdlingResource(String name, Dispatcher dispatcher) {
 this.name = name;
 this.dispatcher = dispatcher;
 dispatcher.setIdleCallback(new Runnable() {
 public void run() {
 ResourceCallback callback = OkHttp3IdlingResource.this.callback;
 if(callback != null) {
 callback.onTransitionToIdle();
 }
 
 }
 });
 }
 
 public boolean isIdleNow() {
 return this.dispatcher.runningCallsCount() == 0;
 }
 
 OkHttp3IdlingResource
  22. @Rule public ActivityTestRule<Main> activityTestRule = new ActivityTestRule<>(Main){
 @Override
 protected void

    beforeActivityLaunched() {
 super.beforeActivityLaunched();
 }
 
 @Override
 protected void afterActivityLaunched() {
 super.afterActivityLaunched();
 }
 
 @Override
 protected void afterActivityFinished() {
 super.afterActivityFinished();
 }
 }; ActivityTestRule
  23. @Rule public IntentTestRule<Main> activityTestRule = new IntentTestRule<>(Main) public IntentsTestRule(Class<T> activityClass)

    {
 super(activityClass);
 }
 public IntentsTestRule(Class<T> activityClass, boolean initialTouchMode) {
 super(activityClass, initialTouchMode);
 }
 public IntentsTestRule(Class<T> activityClass, boolean initialTouchMode,
 boolean launchActivity) {
 super(activityClass, initialTouchMode, launchActivity);
 }
 @Override
 protected void afterActivityLaunched() {
 Intents.init();
 super.afterActivityLaunched();
 }
 @Override
 protected void afterActivityFinished() {
 super.afterActivityFinished();
 Intents.release();
 }
 IntentTestRule
  24. public class CustomActivityTestRule<T extends Activity> extends ActivityTestRule<T> {
 
 public

    CustomActivityTestRule(Class<T> activityClass) {
 super(activityClass);
 }
 
 public CustomActivityTestRule(Class<T> activityClass, boolean initialTouchMode) {
 super(activityClass, initialTouchMode);
 }
 
 
 @Override
 protected void afterActivityLaunched() {
 Intents.init();
 super.afterActivityLaunched();
 }
 
 @Override
 protected void afterActivityFinished() {
 super.afterActivityFinished();
 Intents.release();
 }
 CustomActivityTestRule
  25. public interface TestRule {
 Statement apply(Statement base, Description description);
 }

    public class UiThreadTestRule implements TestRule {
 private static final String LOG_TAG = "UiThreadTestRule";
 
 @Override
 public Statement apply(final Statement base, Description description) {
 return new UiThreadStatement(base, shouldRunOnUiThread(description));
 }
 
 protected boolean shouldRunOnUiThread(Description description) {
 return description.getAnnotation(UiThreadTest.class) != null;
 } } TestRule
  26. private class ActivityStatement extends Statement {
 
 private final Statement

    mBase;
 
 public ActivityStatement(Statement base) {
 mBase = base;
 }
 
 @Override
 public void evaluate() throws Throwable {
 try {
 if (mLaunchActivity) {
 mActivity = launchActivity(getActivityIntent());
 }
 mBase.evaluate();
 } finally {
 finishActivity();
 }
 }
 } TestRule
  27. public class TraceTestRule implements TestRule {
 
 private Trace trace;


    
 public TraceTestRule(Context context) {
 this.trace = new Trace(context);
 }
 
 @Override
 public Statement apply(final Statement base, Description description) {
 return new Statement() {
 @Override
 public void evaluate() throws Throwable {
 try {
 trace.start();
 base.evaluate();
 } finally {
 trace.end();
 }
 }
 };
 }
 } @Rule
 public TraceTestRule traceTestRule = new TraceTestRule(getTargetContext());
 TestRule
  28. return new Statement() {
 @Override
 public void evaluate() throws Throwable

    {
 List<Throwable> errors = new ArrayList<Throwable>();
 
 startingQuietly(description, errors);
 try {
 base.evaluate();
 succeededQuietly(description, errors);
 } catch (@SuppressWarnings("deprecation") AssumptionViolatedException e) {
 errors.add(e);
 skippedQuietly(e, description, errors);
 } catch (Throwable e) {
 errors.add(e);
 failedQuietly(e, description, errors);
 } finally {
 finishedQuietly(description, errors);
 }
 
 MultipleFailureException.assertEmpty(errors);
 }
 }; public abstract class TestWatcher implements TestRule TestWatcher
  29. public class FailedTest extends TestWatcher {
 
 public FailedTest() {


    uiAutomation = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 }
 
 
 @Override
 protected void failed(Throwable e, Description description) {
 super.failed(e, description);
 String fileNameBase = getFileNameWithoutExtension(description);
 saveScreenshot(fileNameBase);
 saveInfo(fileNameBase);
 }
 
 TestWatcher
  30. public class FailedTest extends TestWatcher {
 
 public FailedTest() {


    uiAutomation = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 }
 
 
 @Override
 protected void failed(Throwable e, Description description) {
 super.failed(e, description);
 String fileNameBase = getFileNameWithoutExtension(description);
 saveScreenshot(fileNameBase);
 saveInfo(fileNameBase);
 }
 
 @Override
 protected void succeeded(Description description) {
 super.succeeded(description);
 }
 
 @Override
 protected void skipped(AssumptionViolatedException e, Description description) {
 super.skipped(e, description);
 }
 TestWatcher
  31. public class RuleChain implements TestRule
 public RuleChain ruleChain = RuleChain.outerRule(new

    LoggingRule("outer rule")
 .around(new LoggingRule("middle around rule")
 .around(new LoggingRule("inner around rule”)))); RuleChain
  32. public class RuleChain implements TestRule{
 public RuleChain ruleChain = RuleChain.outerRule(new

    LoggingRule("outer rule")
 .around(new LoggingRule("middle around rule")
 .around(new LoggingRule("inner around rule”)))); Starting outer rule Starting middle rule Starting inner rule Finishing inner rule Finishing middle rule Finishing outer rule RuleChain
  33. public CustomActivityTestRule<Main> activityRule = new CustomActivityTestRule<>(Main.class);
 
 
 @Rule
 public

    RuleChain chain = RuleChain.outerRule(new FailedTest() .around(activityRule);

  34. public CustomActivityTestRule<Main> activityRule = new CustomActivityTestRule<>(Main.class);
 
 
 @Rule
 public

    RuleChain chain = RuleChain.outerRule(new FailedTest() .around(activityRule);
 
 @Rule
 public RuleChain chain = RuleChain.outerRule(new FailedTest()) .around(new TraceTestRule()) .around(activityRule);

  35. public class Device {
 public Device() {
 }
 
 private

    static boolean deviceEquals(String device) {
 return Build.DEVICE.equals(device);
 }
 
 public static class Genymotion implements Condition {
 public Genymotion() {
 }
 
 public boolean isSatisfied() {
 return Device.deviceEquals("vbox86p");
 }
 }
 }
 AndroidTestRules
  36. @Before
 public void grantPhonePermission() {
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {


    getInstrumentation().getUiAutomation().executeShellCommand(
 "pm grant " + getTargetContext().getPackageName()
 + " android.permission.CALL_PHONE");
 }
 }
  37. afterEvaluate {
 tasks.each { task ->
 if (task.name.startsWith('connectedAndroidTest')) {
 task.dependsOn

    grantAnimationPermissions
 }
 }
 }
 devices=$($adb devices | grep -v 'List of devices' | cut -f1 | grep '.')
 
 for device in $devices; do
 echo "Setting permissions to device" $device "for package" $package
 $adb -s $device shell pm grant $package android.permission.xxxx done
  38. Anton Batishchev Anton Malinskiy Chiu-ki Chan Erik Hellman Friedger Müffke

    Iordanis Giannakakis Jake Wharton Jose Alcérreca Michael Bailey Paul Blundell Stephan Linzner Valera Zakharov Xavi Rigau ATSL Spoon Fork TestButler Burst RxPresso AndroidTestRules