# libcvautomation: Writing Application Tests

libcvautomation 1.3

- Main Page
- Related Pages
- Classes
- Files

Writing Application Tests

Author:
  Bradlee Speice <bspeice@uncc.edu>

Date:
  7/23/2012

## Audience

- This document was written for people with some intermediate knowledge of BASH.
- Screenshot experience is required - being able to create screenshots of windows using GIMP, the `import` command from ImageMagick, or something similar.
- Required for working with libcvautomation internals (not needed strictly for writing application testing):
  - Intermediate-level C knowledge required for interfacing with libcvautomation. There isn't much complicated going on with libcvautomation itself, but you need to know to use cvaOpenDisplay() for grabbing a display and then cvaCloseDisplay() for closing it later for example.
  - C++ is available, but currently only as `extern "C"` style bindings.
  - Python bindings are in progress as of time-of-writing

## Purpose

- This document is intended to outline the libcvautomation testing library for GUI applications and its two reference programs `cva-match` and `cva-input`
- These programs allow you to automate mouse and keyboard events in response to what appears on screen - for example, clicking a button based on an image of that button on screen.

## Using Libcvautomation

- Since libcvautomation is a shared-object library intended to bundle a lot of functionality in one area, we must use external programs to agin access to the functions of libcvautomation.
- Two reference programs have been included to make this easy - `cva-match` and `cva-input`
- The reference programs are fairly full-featured, and expose most of libcvautomation:
  - `cva-match` allows you to match multiple image files against a root image providing very fine control over how specific the match is
  - `cva-input` allows you to drive the X11 server using the XTest extension - for example, clicking on a button from image, clicking a key on the keyboard, and more.
- These two programs should implement all functionality needed for GUI automation. Please contact bspeice@uncc.edu if you have suggestions for extra functionality, patches, comments, etc.
- Finally, if you want to write your own programs using libcvautomation, the headers are located on your system. Use:

       #include <libcvautomation/libcvautomation.h>

  to include all necessary header files. See the "Files" tab above to get an idea of what functionality exists.
  Note:
    Intermediate C or C++ knowledge is required for programming with libcvautomation. C++ is currently only supported through `extern "C"`, and full C++ bindings are not currently planned. Libcvautomation itself is incredibly simple, but interfaces with a few API's (Xlib, libcv) that it is helpful to have an idea of how to use.

## Application Testing

Now we get into the good stuff. The basic process for application testing is as follows:

- Create a sequence of screenshots for all mouse-clicks
- Create a testing wrapper in BASH for automating the application
- Test the wrapper and tune any necessary options

### Creating the Screenshot Sequence

- This process creates a set of screenshots by which libcvautomation can drive the X11 server
- The process is simple - create a screenshot of all buttons you would like to click in an application test, or location where you would like to move the mouse, etc.
- This can be accomplished a number of different ways - using GIMP, the `import` command, or any other screenshot program. Additionally, libcvautomation will support any image format that OpenCV does. At the time of writing, these are:
  - Windows bitmaps - `*.bmp`, `*.dib`
  - JPEG files - `*.jpeg`, `*.jpg`, `*.jpe`
  - JPEG 2000 files - `*.jp2`
  - Portable Network Graphics - `*.png`
  - Portable image format - `*.pbm`, `*.pgm`, `*.ppm`
  - Sun rasters - `*.sr`, `*.ras`
  - TIFF files - `*.tiff`, `*.tif`

- Some tips on creating screenshots:

  - Use as distinct an image as possible in a screenshot. For example, the following images look very similar, but can do very different things:
    - The large amount of grey-space in each of the images can be very confusing. While the text itself is different, the overwhelming amount of grey space can result in a false positive. Limiting the space of the screenshot can be useful:
    - Limiting the button size in this case helps the program identify what button you want to click, but in general you want to include as much detail as possible.
  - Be careful of where an image may appear multiple times in a screenshot. For example, a "Help" button on a dialog may get confused with the "Help" menu at the top of the screen.

### Create a Testing Wrapper

- This is where the BASH knowledge comes into play. We are going to write a script that will run your application test, to make sure that the GUI is functioning correctly.
- The following is the (strongly) recommended process, but is not strictly necessary to follow this. The way I'm going to explain this is by giving an example test I wrote, and explain what is going on:

       #!/bin/bash
       #This is an application test involving libcvautomation and libreoffice
       . /etc/libcvautomation_funcs
       set -o errexit

       #Changing any wrapper parameters should go here

       start_libreoffice_writer ()
       {
          click_i "screens/gnome-1_menu.png" "screens/kde-1_menu.png"
          click_i "screens/gnome-2_officeMenu.png" "screens/kde-2_officeMenu.png"
          hover_i "screens/gnome-3_LibreOfficeWriter.png" "screens/kde-3_LibreOfficeWriter.png"
          jiggle_mouse
          click
          sleep 30
       }

       close_libreoffice_writer()
       {
          click_i "screens/gnome-4_fileMenu.png" "screens/kde-4_fileMenu.png"
          click_i "screens/gnome-5_fileExit.png" "screens/kde-5_fileExit.png"
          click_i "screens/gnome-6_discard.png" "screens/kde-6_discard.png"
       }

       start_libreoffice_writer
       close_libreoffice_writer

       #!/bin/bash
       #This is an application test involving libcvautomation and libreoffice
       . /etc/libcvautomation_funcs
       set -o errexit

       #Changing any wrapper parameters should go here

- The purpose of these lines is just the standard BASH header. Additionally, we import a wrapper created for libcvautomation to make our job easier. Please note that this is the default directory for the wrapper, your installation may be different. Use the command `locate libcvautomation_funcs` to find it on your computer. The wrapper itself is a handful of macros used to make our job easy.
- The `set` line will abort the test if an error is ever encountered - for example, no images are found.
- Changing any wrapper parameters should go after sourcing the wrapper functions. See Environment Variables for more information.

       start_libreoffice_writer ()
       {
          click_i "screens/gnome-1_menu.png" "screens/kde-1_menu.png"
          click_i "screens/gnome-2_officeMenu.png" "screens/kde-2_officeMenu.png"
          hover_i "screens/gnome-3_LibreOfficeWriter.png" "screens/kde-3_LibreOfficeWriter.png"
          jiggle_mouse
          click
          sleep 30
       }

- This is the actual body of work done by libcvautomation
- `click_i` is a function to click the mouse at an image - in this case, the gnome or kde menu.
  - Because of how the cva-input program is designed, you can give it multiple images, and it will only select the one currently available. See the Appendix of Wrapper Functions and Environment Variables for more information on how to use this (`TOLERANCE` specifically)
  - Additionally, the wrapper (by default) will wait for an image to appear before clicking on it. This way, you can string together click_i commands even when the program may need to wait a while on processing. Make sure to read up on the `TIMEOUT` option to learn how to use this.
  - By using the function `click_i`, we make things a bit more readable - the full command line is `cva-input -s 'icmouseclick <filename>'`
  - See the Appendix of Wrapper Functions and Environment Variables for a list of all functions available in the wrapper.
- `hover_i` is a function to move the mouse to an image - in this case, move it over the LibreOffice menu item.
- Then we jiggle the mouse to make sure that the item activates, click, and wait for the program to start up.

       close_libreoffice_writer()
       {
          click_i "screens/gnome-4_fileMenu.png" "screens/kde-4_fileMenu.png"
          click_i "screens/gnome-5_fileExit.png" "screens/kde-5_fileExit.png"
          click_i "screens/gnome-6_discard.png" "screens/kde-6_discard.png"
       }

- Use the `click_i` function to close down LibreOffice writer - Find the "File" menu, click "Exit", and then make sure to discard all changes.

       start_libreoffice_writer
       close_libreoffice_writer

- Actually run the functions given.
- Please note that this is a fairly trivial example. The full list of commands available in the wrapper is given in Appendix of Wrapper Functions and Environment Variables

### Testing the Testing Wrapper

- First things first, run through the testing wrapper to make sure that everything is O.K.
- If you need to, there are a few environment variables you can set to change how the wrapper works. See Environment Variables for more information on how these work.
- A full list of commands provided by the wrapper is available at Functions

Note:
  These options are controlled using the testing script as demonstrated above. Any modifications to the following values should be done at the line:

       #Changing any wrapper parameters should go here

## Wrapping Up

- At this point you should have all the information you need to write your own application tests. The libcvautomation library and reference programs were designed to be simple and powerful, but if you invest the time to learn them and some expert BASH scripting, you can do some very complex things.
  - For example, integrating a Test Anything Protocol wrapper into your scripts as well.
- If you have questions, comments, concerns, suggestions, or feedback in general, feel free to let me know at bspeice@uncc.edu.

All Classes Files Functions Defines