UI Testing
Overview
The Test module provides functions to emulate clicks, key presses, encoder turns, time passing, and compare the UI with reference images.
These functions can be easily used in any test framework (such as Unity, GoogleTest, etc.), and assertions can be performed to check if, for example:
A widget's value is different from the expected value after emulating user inputs.
The values are incorrect after some time has passed.
The screen's content is different from the reference image.
Some event functions are not triggered.
Etc.
Note that it is assumed the tests are performed on a desktop or server environment, where there are no memory constraints.
Usage
The Test module can be enabled by LV_USE_TEST
, and it consists of the following components:
Helpers
Display emulation
Input device emulation
Screenshot comparison
Helpers
Time
To emulate elapsed time, two functions can be used:
lv_test_wait(ms): Emulates that
ms
milliseconds have elapsed, but it also callslv_timer_handler
after each millisecond. This is useful to check if events (e.g., long press, long press repeat) and timers were triggered correctly over time.lv_test_fast_forward(ms): Jumps
ms
milliseconds ahead and callslv_timer_handler
only once at the end.
lv_refr_now(NULL) is called at the end of both functions to ensure that animations and widget coordinates are recalculated.
lv_refr_now(NULL) can also be called manually to force LVGL to refresh the emulated display.
Memory Usage
If LV_USE_STDLIB_MALLOC
is set to LV_STDLIB_BUILTIN
, memory usage and memory leaks can be monitored.
size_t mem1 = lv_test_get_free_mem();
<create and delete items>
size_t mem2 = lv_test_get_free_mem();
if(mem1 != mem2) fail();
It might make sense to create and delete items in a loop many times and add a small tolerance to the memory leakage test. This might be needed due to potential memory fragmentation. Empirically, a tolerance of 32 bytes is recommended.
if(LV_ABS((int64_t)mem2 - (int64_t)mem1) > 32) fail();
Display Emulation
By calling lv_test_display_create(hor_res, ver_res), a dummy display can be created.
It functions like any other normal display, but its content exists only in memory.
When creating this display, the horizontal and vertical resolutions must be passed. Internally,
a framebuffer will be allocated for this size, and XRGB8888
color format will be set.
The resolution and color format can be changed at any time by calling lv_display_set_resolution and lv_display_set_color_format.
Input Device Emulation
By calling lv_test_indev_create_all, three test input devices will be created:
A pointer (for touch or mouse)
A keypad
An encoder
For example, this is how a scroll gesture can be emulated:
lv_test_mouse_move_to(20, 30);
lv_test_mouse_press();
lv_test_wait(20);
lv_test_mouse_move_by(0, 100);
lv_test_wait(20);
lv_test_mouse_release();
lv_test_wait(20);
It is recommended to add lv_test_wait after user actions to ensure that the new state and coordinates are read and applied from the input device.
After that, the user can check if the given widget was really scrolled by getting the Y coordinate of a child.
int32_t y_start = lv_obj_get_y(child);
<scroll emulation>
int32_t y_end = lv_obj_get_y(child);
if(y_start + 100 != y_end) fail();
Please refer to lv_test_indev.h
for the list of supported input device emulation functions.
Screenshot Comparison
bool lv_test_screenshot_compare(const char * fn_ref)
is a useful function
to compare the content of the emulated display with reference PNG images.
The screenshot comparison uses libpng, so it needs to be linked to LVGL when this feature is required.
To avoid making the entire Test module dependent on libpng, screenshot comparison can be individually enabled by
LV_USE_TEST_SCREENSHOT_COMPARE
.
This function works in a practical way:
If the folder(s) referenced in
fn_ref
do not exist, they will be created automatically.If the reference image is not found, it will be created automatically from the rendered screen.
If the comparison fails, an
<image_name>_err.png
file will be created with the rendered content next to the reference image.If the comparison fails, the X and Y coordinates of the first divergent pixel, along with the actual and expected colors, will also be printed.
The reference PNG images should have a 32-bit color format and match the display size.
The test display's content will be converted to XRGB8888
to simplify comparison with the reference images.
The conversion is supported from the following formats (i.e., the test display should have a color
format from any of these):
To read and decode PNG images and to store the converted rendered image, a few MBs of RAM are dynamically allocated using the standard malloc
(not lv_malloc).