Slide 1

Slide 1 text

Espresso Beyond the basics

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

onView(withId(R.id.button_take_photo))
 .perform(click())
 .check(matches(isDisplayed()));


Slide 4

Slide 4 text

onView(withId(R.id.button_take_photo))
 .perform(click())
 .check(matches(isDisplayed()));


Slide 5

Slide 5 text

Structure

Slide 6

Slide 6 text

Instrumentation

Slide 7

Slide 7 text

Instrumentation MonitorningInstrumentation

Slide 8

Slide 8 text

Instrumentation MonitorningInstrumentation AndroidJunitRunner

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

public static ViewInteraction onView(final Matcher viewMatcher) {
 return BASE.plus(new ViewInteractionModule(viewMatcher)).viewInteraction();
 }

Slide 16

Slide 16 text

BaseLayerComponent

Slide 17

Slide 17 text

BaseLayerModule UiControllerModule BaseLayerComponent

Slide 18

Slide 18 text

BaseLayerModule ActivityLifeCycleMonitor Context Looper AsyncTaskPoolMonitor Executor ActivityRootLister EventInjector FailureHandler UiControllerModule Recycler BaseLayerComponent

Slide 19

Slide 19 text

BaseLayerModule ActivityLifeCycleMonitor Context Looper AsyncTaskPoolMonitor Executor ActivityRootLister EventInjector FailureHandler UiControllerModule Recycler BaseLayerComponent

Slide 20

Slide 20 text

BaseLayerModule ActivityLifeCycleMonitor Context Looper AsyncTaskPoolMonitor Executor ActivityRootLister EventInjector FailureHandler UiControllerModule Recycler BaseLayerComponent

Slide 21

Slide 21 text

BaseLayerModule ActivityLifeCycleMonitor Context Looper AsyncTaskPoolMonitor Executor ActivityRootLister EventInjector FailureHandler UiControllerModule Recycler BaseLayerComponent UiController

Slide 22

Slide 22 text

BaseLayerComponent

Slide 23

Slide 23 text

FailureHolder BaseLayerComponent FailureHandler ActivityRootLister InteractionComp IdlingRegistry

Slide 24

Slide 24 text

FailureHolder BaseLayerComponent FailureHandler ActivityRootLister InteractionComp InteractionModule Matcher Matcher ViewFinder View IdlingRegistry

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

Synchronization

Slide 27

Slide 27 text


 perform(click());
 
 MainActivityTest


Slide 28

Slide 28 text


 perform(click());
 new GeneralClickAction(Tap.SINGLE, VISIBLE_CENTER, Press.FINGER)); 
 MainActivityTest
 
 ViewActions


Slide 29

Slide 29 text


 perform(click());
 new GeneralClickAction(Tap.SINGLE, VISIBLE_CENTER, Press.FINGER)); 
 MotionEvents.sendDown(uiController, coordinates, precision);
 
 MainActivityTest
 
 ViewActions
 
 Tapper


Slide 30

Slide 30 text


 perform(click());
 new GeneralClickAction(Tap.SINGLE, VISIBLE_CENTER, Press.FINGER)); 
 MotionEvents.sendDown(uiController, coordinates, precision);
 
 uiController.injectMotionEvent(motionEvent);
 
 MainActivityTest
 
 ViewActions
 
 Tapper
 
 MotionEvents


Slide 31

Slide 31 text

InjectKeyEvent loopMainThreadUntilIdle

Slide 32

Slide 32 text

InjectKeyEvent loopMainThreadUntilIdle loopUntil Asynctask Idling

Slide 33

Slide 33 text

InjectKeyEvent loopMainThreadUntilIdle keyEventExecutor submit(event) loopUntil loopUntil Asynctask Idling KeyInject

Slide 34

Slide 34 text

@Override
 public void loopMainThreadUntilIdle() {
 do {
 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 (!sIdleNow()); } UiControllerImpl.java

Slide 35

Slide 35 text

@Override
 public void loopMainThreadUntilIdle() {
 do {
 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 (!sIdleNow()); } UiControllerImpl.java

Slide 36

Slide 36 text

private final AtomicReference monitor = new AtomicReference(null);
 private final ThreadPoolExecutor pool;
 private final AtomicInteger activeBarrierChecks = new AtomicInteger(0);
 AsyncTaskPoolMonitor.java

Slide 37

Slide 37 text

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 monitor = new AtomicReference(null);
 private final ThreadPoolExecutor pool;
 private final AtomicInteger activeBarrierChecks = new AtomicInteger(0);
 AsyncTaskPoolMonitor.java

Slide 38

Slide 38 text

IdlingResourceRegistry.java

Slide 39

Slide 39 text

public boolean registerResources(final List resourceList) { } public boolean unregisterResources(final List resourceList) {
 }
 IdlingResourceRegistry.java

Slide 40

Slide 40 text

public boolean registerResources(final List resourceList) { } public boolean unregisterResources(final List resourceList) {
 }
 IdlingResourceRegistry.java 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();
 }

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

Guava

Slide 43

Slide 43 text

abstract class WrappingExecutorService implements ExecutorService {
 private final ExecutorService delegate;
 
 protected GuavaWrappingExecutorService(ExecutorService delegate) {
 this.delegate = checkNotNull(delegate);
 }
 
 protected abstract Callable wrapTask(Callable callable);
 
 protected Runnable wrapTask(Runnable command) {
 final Callable wrapped = wrapTask(Executors.callable(command);
 return new Runnable() {
 @Override
 public void run() {
 wrapped.call();
 }
 };
 }
 @Override
 public final void execute(Runnable command) {
 delegate.execute(wrapTask(command));
 }
 } Guava

Slide 44

Slide 44 text

abstract class WrappingExecutorService implements ExecutorService {
 private final ExecutorService delegate;
 
 protected GuavaWrappingExecutorService(ExecutorService delegate) {
 this.delegate = checkNotNull(delegate);
 }
 
 protected abstract Callable wrapTask(Callable callable);
 
 protected Runnable wrapTask(Runnable command) {
 final Callable wrapped = wrapTask(Executors.callable(command);
 return new Runnable() {
 @Override
 public void run() {
 wrapped.call();
 }
 };
 }
 @Override
 public final void execute(Runnable command) {
 delegate.execute(wrapTask(command));
 }
 } Guava

Slide 45

Slide 45 text

abstract class WrappingExecutorService implements ExecutorService {
 private final ExecutorService delegate;
 
 protected GuavaWrappingExecutorService(ExecutorService delegate) {
 this.delegate = checkNotNull(delegate);
 }
 
 protected abstract Callable wrapTask(Callable callable);
 
 protected Runnable wrapTask(Runnable command) {
 final Callable wrapped = wrapTask(Executors.callable(command);
 return new Runnable() {
 @Override
 public void run() {
 wrapped.call();
 }
 };
 }
 @Override
 public final void execute(Runnable command) {
 delegate.execute(wrapTask(command));
 }
 } Guava

Slide 46

Slide 46 text

abstract class WrappingExecutorService implements ExecutorService {
 private final ExecutorService delegate;
 
 protected GuavaWrappingExecutorService(ExecutorService delegate) {
 this.delegate = checkNotNull(delegate);
 }
 
 protected abstract Callable wrapTask(Callable callable);
 
 protected Runnable wrapTask(Runnable command) {
 final Callable wrapped = wrapTask(Executors.callable(command);
 return new Runnable() {
 @Override
 public void run() {
 wrapped.call();
 }
 };
 }
 @Override
 public final void execute(Runnable command) {
 delegate.execute(wrapTask(command));
 }
 } Guava

Slide 47

Slide 47 text

public class IdlingExecutorService extends GuavaWrappingExecutorService {
 private final CountingIdlingResource mIdlingResource;
 
 public IdlingResourceExecutorService(ExecutorService delegate,
 CountingIdlingResource idling) {
 super(delegate);
 mIdlingResource = idling;
 }
 


Slide 48

Slide 48 text

@Override
 protected Callable wrapTask(Callable callable) {
 return new WrappedCallable<>(callable);
 }
 
 private final class WrappedCallable implements Callable {
 private final Callable delegate;
 
 public WrappedCallable(Callable delegate) {
 this.delegate = delegate;
 }
 
 @Override
 public T call() throws Exception {
 mIdlingResource.increment();
 T call;
 try {
 call = delegate.call();
 } finally {
 mIdlingResource.decrement();
 } } }


Slide 49

Slide 49 text

@Override
 protected Callable wrapTask(Callable callable) {
 return new WrappedCallable<>(callable);
 }
 
 private final class WrappedCallable implements Callable {
 private final Callable delegate;
 
 public WrappedCallable(Callable delegate) {
 this.delegate = delegate;
 }
 
 @Override
 public T call() throws Exception {
 mIdlingResource.increment();
 T call;
 try {
 call = delegate.call();
 } finally {
 mIdlingResource.decrement();
 } } }


Slide 50

Slide 50 text

RxJava

Slide 51

Slide 51 text

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();
 }
 };
 }
 RxJava

Slide 52

Slide 52 text

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();
 }
 };
 }
 RxJava

Slide 53

Slide 53 text

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();
 }
 };
 }
 RxJava

Slide 54

Slide 54 text

@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

Slide 55

Slide 55 text

@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

Slide 56

Slide 56 text

@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

Slide 57

Slide 57 text

RxJavaPlugins.getInstance().registerSchedulersHook(RxSchedulerHook.get());
 RxJava

Slide 58

Slide 58 text

OkHttp3IdlingResource

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

@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

Slide 61

Slide 61 text

Rules

Slide 62

Slide 62 text

@Rule public ActivityTestRule activityTestRule = new ActivityTestRule<>(Main){
 @Override
 protected void beforeActivityLaunched() {
 super.beforeActivityLaunched();
 }
 
 @Override
 protected void afterActivityLaunched() {
 super.afterActivityLaunched();
 }
 
 @Override
 protected void afterActivityFinished() {
 super.afterActivityFinished();
 }
 }; ActivityTestRule

Slide 63

Slide 63 text

@Rule public ActivityTestRule activityTestRule = new ActivityTestRule<>(Main){
 @Override
 protected void beforeActivityLaunched() {
 super.beforeActivityLaunched();
 }
 
 @Override
 protected void afterActivityLaunched() {
 super.afterActivityLaunched();
 }
 
 @Override
 protected void afterActivityFinished() {
 super.afterActivityFinished();
 }
 }; ActivityTestRule

Slide 64

Slide 64 text

@Rule public IntentTestRule activityTestRule = new IntentTestRule<>(Main) IntentTestRule

Slide 65

Slide 65 text

@Rule public IntentTestRule activityTestRule = new IntentTestRule<>(Main) 
 
 public IntentsTestRule(Class 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

Slide 66

Slide 66 text

public class CustomActivityTestRule extends ActivityTestRule {
 
 public CustomActivityTestRule(Class activity) {
 super(activity);
 }
 
 public CustomActivityTestRule(Class activity, boolean initialTouchMode) {
 super(activity, initialTouchMode);
 }
 
 
 @Override
 protected void afterActivityLaunched() {
 Intents.init();
 super.afterActivityLaunched();
 }
 
 @Override
 protected void afterActivityFinished() {
 super.afterActivityFinished();
 Intents.release();
 } CustomActivityTestRule

Slide 67

Slide 67 text

public class CustomActivityTestRule extends ActivityTestRule {
 
 public CustomActivityTestRule(Class activity) {
 super(activity);
 }
 
 public CustomActivityTestRule(Class activity, boolean initialTouchMode) {
 super(activity, initialTouchMode);
 }
 
 
 @Override
 protected void afterActivityLaunched() {
 Intents.init();
 super.afterActivityLaunched();
 }
 
 @Override
 protected void afterActivityFinished() {
 super.afterActivityFinished();
 Intents.release();
 } CustomActivityTestRule

Slide 68

Slide 68 text

public interface TestRule {
 Statement apply(Statement base, Description description);
 } TestRule

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

private class ActivityStatement extends Statement {
 
 private final Statement mBase;
 
 public ActivityStatement(Statement base) {
 mBase = base;
 }
 
 @Override
 public void evaluate() throws Throwable {
 try {
 if (mLaunchActivity) {
 act = launchActivity(getActivityIntent());
 }
 mBase.evaluate();
 } finally {
 finishActivity();
 }
 }
 } TestRule

Slide 71

Slide 71 text

public class TraceTestRule implements TestRule {
 
 private Trace trace;
 
 @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();
 }
 }
 };
 }
 } TestRule

Slide 72

Slide 72 text

public class TraceTestRule implements TestRule {
 
 private Trace trace;
 
 @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 TestRule

Slide 73

Slide 73 text

public abstract class TestWatcher implements TestRule TestWatcher

Slide 74

Slide 74 text

return new Statement() {
 @Override
 public void evaluate() throws Throwable {
 List errors = new ArrayList();
 
 startingQuietly(description, errors);
 try {
 base.evaluate();
 succeededQuietly(description, errors);
 } catch (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

Slide 75

Slide 75 text

return new Statement() {
 @Override
 public void evaluate() throws Throwable {
 List errors = new ArrayList();
 
 startingQuietly(description, errors);
 try {
 base.evaluate();
 succeededQuietly(description, errors);
 } catch (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

Slide 76

Slide 76 text

public class FailedTest extends TestWatcher {
 
 public FailedTest() {
 uiAutomation = UiDevice.getInstance();
 }
 
 
 @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

Slide 77

Slide 77 text

public class FailedTest extends TestWatcher {
 
 public FailedTest() {
 uiAutomation = UiDevice.getInstance();
 }
 
 
 @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

Slide 78

Slide 78 text

public class FailedTest extends TestWatcher {
 
 public FailedTest() {
 uiAutomation = UiDevice.getInstance();
 }
 
 
 @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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

public NewActivityTestRule activityRule = new NewActivityTestRule<>(Main.class);
 


Slide 83

Slide 83 text

public NewActivityTestRule activityRule = new NewActivityTestRule<>(Main.class);
 
 
 @Rule
 public RuleChain chain = RuleChain.outerRule(new FailedTest() .around(activityRule);


Slide 84

Slide 84 text

public NewActivityTestRule activityRule = new NewActivityTestRule<>(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);


Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

Permissions

Slide 87

Slide 87 text

No content

Slide 88

Slide 88 text

@Before
 public void grantPhonePermission() {
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
 getInstrumentation().getUiAutomation().executeShellCommand(
 "pm grant " + getTargetContext().getPackageName()
 + " android.permission.CALL_PHONE");
 }
 }

Slide 89

Slide 89 text

afterEvaluate {
 tasks.each { task ->
 if (task.name.startsWith('connectedAndroidTest')) {
 task.dependsOn grantAnimationPermissions
 }
 }
 }


Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

ATSL Spoon Fork TestButler Burst RxPresso AndroidTestRules

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

Cảm ơn

Slide 95

Slide 95 text

Cảm ơn Agoda đang tuyển dụng

Slide 96

Slide 96 text

+IñakiVillar @inyaki_mwc Cảm ơn Agoda đang tuyển dụng