Tuesday, June 2, 2015

Recording tests on Android (neither root, nor KitKat required)

A test suite is good only when provides a good feedback. Testing mobile apps is cumbersome, and far from robust (actually all UI tests are like that). A meaningful test report is inevitable. That is why, I really like to have executions of my tests recorded. Such recordings are great thing to avoid a repeated execution of the test to find out why it failed (repeated execution of tests should be avoided as plague).

It is awesome that Google added a a native support for recording of your Android 4.4.x+ device screen, but what the other folks with lower Android versions. We can not afford to test only on 4.4+, as it is wise to support at least 4.0+. A rooted device is not the answer for me, as we need to test on real devices, devices which are actually used by our customers.

OK, all Android versions are capable to take a screen capture, so why not to use this feature. The following describes small bash scripts, which in simple words create a video (actually a .gif with 2fps) from such screen captures. It is then easy to use them to record your functional UI tests (showcased on Appium tests).

Firstly, the script which takes screenshots until not terminated into a specified directory on your device:

#!/bin/bash
#take-screenshots.sh
DIR=/sdcard/test-screenshots
adb -s $1 shell rm -r $DIR > /dev/null 2>&1
adb -s $1 shell mkdir $DIR > /dev/null 2>&1
for (( i=1; ; i++ ))
do
 name=`date +%s`
 adb -s $1 shell screencap -p "$DIR/$name.png"
done
You can try it by executing ./take-screenshots.sh [serialNumberOfDevice].

Secondly, the script which retrieves taken screenshots from devices into your computer, re-sizes them into smaller resolution, and finally creates an animated .gif:

#!/bin/bash
#pull-screenshots-and-make-video.sh
DIR_REMOTE=/sdcard/test-screenshots
mkdir "$1"
cd "$1"
adb -s $1 pull $DIR_REMOTE
echo "Resizing screenshots to smaller size!"
mogrify -resize 640x480 *.png
echo "Converting to .gif."
convert -delay 50 *.png "$1"-test.gif
echo "Clearing..."
cp "$1"-test.gif ..
cd ..
rm -rf "$1"
Try it by executing ./pull-screenshots-and-make-video.sh [serialNumberOfDevice] [pathToDirectoryIntoWhichSaveScreenshots]. Just to note that it uses the imagemagic and its sub packages.

Here is an example of .gif created by scripts above, while sending encrypted files through the PhoneX app for a secure communication:
So we have some scripts to execute (indeed there are things to improve, a parameter checking etc.). There are various ways how to use them in your tests, all depend on what testing framework you are using, and in what language your tests are written in. We use the Appium, and its Java client. Following shows executing of the first (take-screenshots.sh) script in the beginning of each test class:
public class AbstractTest {
    private Process takeScreenshotsProcess = null;

    @Before
    protected void setupDevice1() throws Exception {
        takeScreenshotsProcess = startTakingOfScreenshots(DEVICE_1_NAME);
        //for readability omitted Appium API calls to setup device for testing
    }

    protected Process startTakingOfScreenshots(String deviceName) throws Exception {
        String[] cmd = { "sh/take-screenshot-on-device.sh", getDeviceSerialNumber(deviceName)};
        return Runtime.getRuntime().exec(cmd);
    }

    @After
    public void tearDown() {
        if(takeScreenshotsProcess != null) {
           takeScreenshotsProcess.destroyForcibly();
        }
    }
}
Hopefully the code above is somehow self explanatory. It starts taking of screenshots before Appium API calls prepare a device for a testing (installs APK, etc.). The same pattern can be used for any number of devices.

Next steps are to use the pull-screenshots-and-make-video.sh script in the end of your CI job (e.g. Jenkins). I prefer fine granular CI jobs, which are short to execute, to provide a quick feedback. Therefore, each job is a one test (or matrix of tests), and that is why, starting of taking screenshots is done in the @Before method, and terminated in the @After method.

Please, bear in mind, that previous are just examples. They need to be polished and altered to ones needs. Enjoy testing.

1 comment:

  1. Nice post! I have now installed Total Recall phone call recorder app which is working fine and now its available at Play Store in just half price with 90 days trial session.

    ReplyDelete