Oto jak ja to robię w tej chwili:
public class MainScreenTest extends BaseStatelessBlackBoxEspressoTest<LaunchActivity> {
public MainScreenTest() {
super(LaunchActivity.class);
}
public void testMainScreen() {
// Unfortunately this must be explicitly called in each test :-(
setUpFailureHandler();
onView(withId(R.id.main_circle)).
check(matches(isDisplayed()));
}
}
Moja baza Espresso klasa Test ustawia niestandardową FailureHandler (lubię przy użyciu klasy bazowej posiadać wiele innych wspólnych kierunkowym):
public abstract class BaseStatelessBlackBoxEspressoTest<T extends Activity> extends BaseBlackBoxTest<T> {
public BaseStatelessBlackBoxEspressoTest(Class clazz) {
super(clazz);
}
@Before
public void setUp() throws Exception {
super.setUp();
getActivity();
}
public void setUpFailureHandler() {
// Get the test class and method. These have to match those of the test
// being run, otherwise the screenshot will not be displayed in the Spoon
// HTML output. We cannot call this code directly in setUp, because at
// that point the current test method is not yet in the stack.
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
String testClass = trace[3].getClassName();
String testMethod = trace[3].getMethodName();
Espresso.setFailureHandler(new CustomFailureHandler(
getInstrumentation().getTargetContext(),
testClass,
testMethod));
}
private static class CustomFailureHandler implements FailureHandler {
private final FailureHandler mDelegate;
private String mClassName;
private String mMethodName;
public CustomFailureHandler(Context targetContext, String className, String methodName) {
mDelegate = new DefaultFailureHandler(targetContext);
mClassName = className;
mMethodName = methodName;
}
@Override
public void handle(Throwable error, Matcher<View> viewMatcher) {
try {
mDelegate.handle(error, viewMatcher);
} catch (Exception e) {
SpoonScreenshotAction.perform("espresso_assertion_failed", mClassName, mMethodName);
throw e;
}
}
}
}
... i tutaj jest nieco zmodyfikowany kod screenshot z the Gist posted by Square:
/**
* Source: https://github.com/square/spoon/issues/214#issuecomment-81979248
*/
public final class SpoonScreenshotAction implements ViewAction {
private final String tag;
private final String testClass;
private final String testMethod;
public SpoonScreenshotAction(String tag, String testClass, String testMethod) {
this.tag = tag;
this.testClass = testClass;
this.testMethod = testMethod;
}
@Override
public Matcher<View> getConstraints() {
return Matchers.anything();
}
@Override
public String getDescription() {
return "Taking a screenshot using spoon.";
}
@Override
public void perform(UiController uiController, View view) {
Spoon.screenshot(getActivity(view), tag, testClass, testMethod);
}
private static Activity getActivity(View view) {
Context context = view.getContext();
while (!(context instanceof Activity)) {
if (context instanceof ContextWrapper) {
context = ((ContextWrapper) context).getBaseContext();
} else {
throw new IllegalStateException("Got a context of class "
+ context.getClass()
+ " and I don't know how to get the Activity from it");
}
}
return (Activity) context;
}
public static void perform(String tag, String className, String methodName) {
onView(isRoot()).perform(new SpoonScreenshotAction(tag, className, methodName));
}
}
Chciałbym znaleźć sposób na uniknięcie dzwonienia pod numer setUpFailureHandler()
w każdym teście - proszę dać mi znać, jeśli masz dobry pomysł, jak tego uniknąć!
Użycie SpoonScreenshotAction samo wywoła funkcję FailureHandler Espresso, gdy np. nie znaleziono aktywności. Jest to złe, ponieważ prowadzi to do nieskończonej pętli, a zatem do błędu OutOfMemory. Lepiej użyj Spoon.screenshot() bezpośrednio: '' Łyżka.screenshot (getActivity(), tag, testClassName, testMethodName); '' zamiast SpoonScreenshotAction.perform(); – sebokopter