App & Browser Testing Made Easy

Give your users a seamless experience by testing on 3000+ real devices and browsers. Don't compromise with emulators and simulators

Get Started free
Home Guide Using Native Screenshots for Better Debugging

Using Native Screenshots for Better Debugging

By Tom Collins, Community Contributor -

Different ways are available to assist you in debugging, such as screenshot testing to precisely determine any anomaly. Furthermore, using screenshots for debugging, you can also pinpoint where the software is experiencing a failure. 

This abnormality is either affecting the execution of the app. Or this error could also be causing the malfunctioning of the app in any way that you, as a developer or a tester, did not expect to happen. And do you know what could be the worst thing in this case? 

This could be a minor bug hidden in one of the hundreds of files between those thousand lines of code. However, with  App Automate, you can use screenshots to discover the developed app’s bugs. 

How do Native Screenshots for Debugging help? 

Any case can compel a tester to use screenshots for debugging as it becomes beneficial in simplifying the process. Screenshots also identify any issues related to the UI – the layout or any design-related problems in the app- without writing any test code.

These Screenshots for debugging can also be captured on BrowserStack App Automate, where you will be able to debug and fix the Espresso tests by using – 

  • Screenshots aids
  • Video recording aids 
  • A range of logs pointing out the code errors

Not only these, but you can also configure the options for debugging as per your needs while running your Espresso tests. For those not into coding, Espresso Test Recorder create UI tests for your app without writing any code. 

You need a costly device farm to run the Espresso tests on multiple real devices. But by opting for testing on a Real Device Cloud on BrowserStack. Access 3000+ device-browser-OS combinations.

Test on Real Device Cloud

How to test your Native Apps?

App Automate can provide testing with the help of screenshots while testing both hybrid and native applications. With excellent device coverage, including the latest flagship devices from Android and iOS, teams can integrate testing frameworks – Appium, Espresso, XCUITest, or Flutter, with various Test Dev environments.

  • You can also test under real user scenarios like network simulation, geolocation testing, in-app purchases, push notifications, and preloaded images.
  • In addition, you can easily debug your apps immediately with the help of device and text logs, screenshots, and video recordings for every test execution instance. 

Prerequisites for testing the native apps using Espresso

For testing your app build, you need to have the following things in your inventory – 

  • A mobile OS like an Android OS or iOS: It will help in initiating the execution for your app
  • A URL of the file if it is stored on the cloud: If your app has been stored on the cloud and not on the local server, then a URL of the app is also helpful. 
  • A BrowserStack Account: A BrowserStack Account gives your the access keys required to connect to testing platform 

Testing the Native Apps using BrowserStack

To test the native app, you need to log in to your BrowserStack account. You can capture screenshots for your Espresso tests by utilizing the Spoon framework. The native screenshots can help find the precise screen where the abnormal activity or the failure occurred. You will also be able to see if there are any UI bugs in the code. 

To enable screenshots capture using Spoon framework, you must pass the enableSpoonFramework parameter in the REST API request. This will begin the Espresso test execution. 

Given below is an example.

curl -u "YOUR_USERNAME:YOUR_ACCESS_KEY" \
-X POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/build" \
-d '{"enableSpoonFramework" : true, "devices": ["Samsung Galaxy S8-7.0"], "app": "bs://f7c874f21852ba57957a3fdc33f47514288c4ba4", "testSuite": "bs://e994db8333e32a5863938666c3c3491e778352ff"}' \
-H "Content-Type: application/json"

Steps to capture Screenshots in your Espresso tests

For native Screenshot of testing a native app, the steps are:

  • creating NativeScreenshot.java in your project directory. add the code that is given below:
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Environment;
import androidx.test.runner.screenshot.BasicScreenCaptureProcessor;
import androidx.test.runner.screenshot.ScreenCapture;
import androidx.test.runner.screenshot.Screenshot;
import java.io.File;
import java.io.IOException;
import java.util.regex.Pattern;
public final class NativeScreenshot {
private static String methodName;
private static String className;
private static final Pattern SCREENSHOT_NAME_VALIDATION = Pattern.compile("[a-zA-Z0-9_-]+");
private NativeScreenshot() {}
/**
* Captures screenshot using Androidx Screenshot library and stores in the filesystem.
*Special Cases:
* If the screenshotName contains spaces or does not pass validation, the corresponding
* screenshot is not visible on BrowserStack's Dashboard.
* If there is any runtime exception while capturing screenshot, the method throws
* Exception and the test might fail if exception is not handled properly.
* @param screenshotName a screenshot identifier
* @return path to the screenshot file
*/
public static String capture(String screenshotName) {
StackTraceElement testClass = findTestClassTraceElement(Thread.currentThread().getStackTrace());
className = testClass.getClassName().replaceAll("[^A-Za-z0-9._-]", "_");
methodName = testClass.getMethodName();
EspressoScreenCaptureProcessor screenCaptureProcessor = new EspressoScreenCaptureProcessor();

if (!SCREENSHOT_NAME_VALIDATION.matcher(screenshotName).matches()) {
throw new IllegalArgumentException("ScreenshotName must match " + SCREENSHOT_NAME_VALIDATION.pattern() + ".");
} else {
ScreenCapture capture = Screenshot.capture();
capture.setFormat(Bitmap.CompressFormat.PNG);
capture.setName(screenshotName);

try {
return screenCaptureProcessor.process(capture);
} catch (IOException e) {
throw new RuntimeException("Unable to capture screenshot.", e);
}
}
}

/**
* Extracts the currently executing test's trace element based on the test runner
* or any framework being used.
* @param trace stacktrace of the currently running test
* @return StackTrace Element corresponding to the current test being executed.
*/
private static StackTraceElement findTestClassTraceElement(StackTraceElement[] trace) {
for(int i = trace.length - 1; i >= 0; --i) {
StackTraceElement element = trace[i];
if ("android.test.InstrumentationTestCase".equals(element.getClassName()) && "runMethod".equals(element.getMethodName())) {
return extractStackElement(trace, i);
}

if ("org.junit.runners.model.FrameworkMethod$1".equals(element.getClassName()) && "runReflectiveCall".equals(element.getMethodName())) {
return extractStackElement(trace, i);
}

if ("cucumber.runtime.model.CucumberFeature".equals(element.getClassName()) && "run".equals(element.getMethodName())) {
return extractStackElement(trace, i);
}
}
throw new IllegalArgumentException("Could not find test class!");
}

/**
* Based on the test runner or framework being used, extracts the exact traceElement.
* @param trace stacktrace of the currently running test
* @param i a reference index
* @return trace element based on the index passed
*/
private static StackTraceElement extractStackElement(StackTraceElement[] trace, int i) {
int testClassTraceIndex = Build.VERSION.SDK_INT >= 23 ? i - 2 : i - 3;
return trace[testClassTraceIndex];
}

private static class EspressoScreenCaptureProcessor extends BasicScreenCaptureProcessor {
private static final String SCREENSHOT = "screenshots";

EspressoScreenCaptureProcessor() {
File screenshotDir = new File(String.valueOf(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)), SCREENSHOT);
File classDir = new File(screenshotDir, className);
mDefaultScreenshotPath = new File(classDir, methodName);
}
/**
* Converts the filename to a standard path to be stored on device.
* Example: "post_addition" converts to "1648038895211_post_addition"
* which is later suffixed by the file extension i.e. png.
* @param filename a screenshot identifier
* @return custom filename format
*/
@Override
protected String getFilename(String filename) {
return System.currentTimeMillis() + "_" + filename;
}
}
}

This is how you can edit your test scripts to take native screenshots

After that you need to call the NativeScreenshot.capture(“tag”) method. This will help you to capture the screenshots from your Espresso tests. The sample code has been provided in the snippet.

The tag parameter gives a name to the screenshot, which is stored in you’re detail page of App Automate session detail.

@Test
public void ensureAdditionWorks() {
// test actions
onView(withId(R.id.buttonOne)).perform(click());
onView(withId(R.id.buttonTwo)).perform(click());
onView(withId(R.id.buttonAdd)).perform(click());
// other test actions ...
onView(withId(R.id.editText)).check(matches(withText("33")));

// capture the screenshot and add the 'post_addition' tag to the screenshot
NativeScreenshot.capture("post_addition");
}

Add the debug screenshots parameter in the REST API request to enable screenshots on your Espresso test session.

The following sample cURL command shows the parameters used to enable screenshots on Android v7.1:

curl -u "contentusdigital_6BJuGt:RCQgysY5ofpxBvsEQayp" \
-X POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/build" \
-d '{"debugscreenshots": true, "devices": ["Google Pixel-7.1"], "app": "<app_id>", "testSuite": "<test_suite_id>"}' \
-H "Content-Type: application/json"

View Screenshots of the Test Execution

Now you need to navigate to the App Automate dashboard. On your session detail page, you have to click on the Screenshots tab to view screenshots for every test case. 

An example is given in the following image:

View Screenshots of the Test Execution

Wrapping Up, 

Hopefully, this write-up has shed light on the functioning of BrowserStack App Automate and how it can make a tangible difference towards better debugging. Moreover, with BrowserStack, you can access more than 3000+ real devices and browsers, to run your tests, identify bugs or other anomalies and find resolutions to deliver the best possible product. 

Try App Automate

Tags
Automation Testing Manual Testing

Featured Articles

How to perform Android screenshot testing?

Screenshot Testing: A Detailed Guide

App & Browser Testing Made Easy

Seamlessly test across 20,000+ real devices with BrowserStack