Developing tests using android uiautomator and automating them with Python

« BACK

      Our new task was to develop unit tests on a Honda car test bench, as well as a Python tool to automate the tests, recover the logs, and interact with the USB Multiplexer.

      The main project in our Wind River office is a 7-year long project aiming at developing an operating system, based on android, for Honda cars.
      They are currently in the testing phase, so they asked us to develop some unit tests for it. We were provided with a car test bench to run the tests on.

      The tests we had to do were black-box tests, meaning that they can be launched without an access to the source code, just using the visible elements on the device’s screen. We used the android uiautomator tool in order to do that.

      We were given test cases and we had to program them, first on the USB and then on the Wi-Fi module of the system. We used Android Studio to design the tests.

      Our main goal was to automate the testing procedure. With this in mind we developed a Python tool that launched every tests through Android Debug Bridge. This tool had to recover, parse and save the device logs for every tests. It also had to communicate with an USB Multiplexer, using the tool we had previously developed. The tool uses concurrency programming concepts that I had the chance to see in depth in the Python concurrency class I took at the UIT.
      This way, the test flow could be entirely automated, launching tests on the test bench, automating the USB plugs-in and plugs-out, and recovering the logs for debug purposes.

Here is a peak at the Python thread running the multiple steps to execute one test case

# The unitTests to be run on the device
class _UnitTests(Thread):
    def __init__(self, fifo, testCase = None):
        Thread.__init__(self)
        self._fifo = fifo
        self._testCase = testCase

    def run(self):
        if self._testCase == None or self._testCase == 3 :
            # TEST_CASE_3
            self._test('192.168.43.1:5555','com.example.nathan.benchtest.ExampleInstrumentedTest','TestCase_3_1')
            for i in range(1, 6) :
                nbAdbDevices = _ADB.getConectedAdbDevicesNumber()
                SWITCH.deactivatePort()
                sleep(0.5) # Let the electromagnet reset
                while _ADB.getConectedAdbDevicesNumber() > nbAdbDevices :
                    sleep(0.25)
                SWITCH.setActivePort(i)
                while SWITCH.getActivePort() != i :
                    sleep(0.25)
                print('>>> Wait for phone to be connected via adb')
                while _ADB.getConectedAdbDevicesNumber() < nbAdbDevices :
                    sleep(0.25)
                print('>>> Phone succesfully connected via adb')
                self._test('USB', 'com.example.nathan.benchtest.DeviceHotspotTest','TestCase_3_2')
            self._test(ADB_FCB_ADDRESS,'com.example.nathan.benchtest.ExampleInstrumentedTest','TestCase_3_3')

    def _test(self, device, test_class, test_method, usb = False):
        if usb == "OUT" :
            self._fifo.put(test_method)
            MUTEX_UNITTESTS.acquire()
            port = SWITCH.getActivePort()
            _ADB.runTestMethod(test_class, test_method, device)
            print('>>> WAIT for USB device to be plugged out')
            while SWITCH.getActivePort() != port :
                sleep(0.025)
            print('>>> USB device plugged out!')
        elif usb == "IN":
            self._fifo.put(test_method)
            MUTEX_UNITTESTS.acquire()
            _ADB.runTestMethod(test_class, test_method, device)
            print('>>> WAIT for USB device initialization')
            MUTEX_USB_IN.acquire() # we wait for the USB plug in to be processed ;
            # there should be as many MUTEX_USB_IN.acquire() as there are usb being
            # plugged in during the previous test
            print('>>> USB device initialization completed!')
        else :
            if device != 'USB':
                self._fifo.put(test_method)
                MUTEX_UNITTESTS.acquire()
            _ADB.runTestMethod(test_class, test_method, device)

      The goal of unit tests is to detect potential bugs in your application. So, each time we came across a bug we put together logs, reproduction steps, screenshots and hypothesis on its cause for our colleagues to be able to fix it.

      We learned a lot on the android’s development’s technologies thanks to this assignment.