Use this skill to generate repository-style C++ tests for the OpenHarmony Rosen graphics pixel comparison framework; the target directory is usually graphic_test/test。
Generating a test case is not just writing a test function. A good result requires choosing the right test directory and RSGraphicTestType, following the style of adjacent files, correctly using the framework lifecycle, registering all render nodes that need to stay alive, and when adding a new .cpp , updating graphic_test/test/BUILD.gn。
Key prohibitions
- Do not, in
GetRootNode()->AddChild(...)、AddChildToSubWindow(...)or after creating a custom surface, forgetRegisterNode(...); the node may be released early, and the screenshot will be blank or unstable. - Do not mistakenly write an independent test as
GRAPHIC_TESTS; use it only when multiple test surfaces of the same fixture clearly need to be aggregated into one grid screenshot. - Do not create a new
ohos_unittesttarget for an ordinary graphic test; a newly added.cppshould be added tographic_test/test/BUILD.gnthe existing category sources array in - Do not invent Drawing helpers, test helpers, or RenderService APIs out of thin air; check adjacent files and framework headers first.
- Do not blindly add
FlushImplicitTransactionand sleep in automatic screenshot tests; add them only when manual screenshots, immediately querying render results, or adjacent tests require it. - Do not use image resource paths that cannot be guaranteed to exist; prefer reusing the existing
/data/local/tmp/...path in the same directory, or generate a PixelMap in code.
Starting steps
- Locate the real
graphic_testroot directory in the workspace. - First read
graphic_test/graphic_test_framework/include/rs_graphic_test.h、rs_graphic_test_ext.h, then read the existing test file closest to the requirement. - Before generating, answer these checkpoints:
- Purpose: Which specific rendering behavior or screenshot difference am I verifying?
- Existing: Should I extend an existing test file, or is creating a new one more appropriate?
- Type: Which
RSGraphicTestTypeand which test macro does this scenario correspond to? - Pixels: What colors, images, borders, grids, or boundary values in the screenshot make the difference visible and stable?
- Build: If adding a new file, which sources array of
test/BUILD.gnshould it be added to?
- After confirming the scenario, read only the relevant reference files in this skill:
references/framework-lifecycle.md: framework lifecycle, macros, screenshots, node lifecycle.references/test-taxonomy-build.md: test placement location andtest/BUILD.gnupdate rules.references/code-patterns.md: idiomatic ways to write nodes, images, Canvas, animations, manual screenshots, subwindows, and PixelMap.references/templates.md: compact starting template.
- Prefer following the style of local adjacent files. Reference files explain patterns; existing code is the authority on includes, helper names, and API availability.
- At minimum, perform text-level checks: macro names, namespace, include,
RegisterNode, source list entry, and whether fabricated APIs exist.
Generation process
1. Determine the test classification
Choose the directory and RSGraphicTestType:
| Scenario | Common directory | Common type |
|---|---|---|
| Node appearance, background, foreground, geometry, content display | rs_display_effect/property_display or rs_display_effect/content_display |
CONTENT_DISPLAY_TEST |
| animation protocols, curves, custom modifier animations | rs_display_effect/animation |
ANIMATION_TEST |
| NG shader/filter/effect/mask/shape visual effects | rs_effect_feature/... |
EFFECT_TEST |
| open capability APIs such as PixelMap, font, symbol | open_capability/... |
usually CONTENT_DISPLAY_TEST, or reuse existing local types |
| dirty regions, HWC, GPU composer, hybrid render, performance-related rendering | rs_perform_feature/... |
reuse existing local types, commonly CONTENT_DISPLAY_TEST、GPU_COMPOSER_TEST、HYBRID_RENDER_TEST |
| surface capture, screen capture, multi-screen, accessibility, watermark, render group | rs_func_feature/... |
usually CONTENT_DISPLAY_TEST |
| framework surface behavior | rs_framework/... |
usually CONTENT_DISPLAY_TEST |
| Effect Kit NDK filter | effect_kit/... |
EFFECT_TEST |
If a related file already exists, prefer extending that file; only add a new file when the new feature boundary is clear and appending would make the old file messy.
2. Choose the test macro
- Ordinary automatic screenshot pixel tests use
GRAPHIC_TEST(TestClass, TYPE, TestName)。 GRAPHIC_TEST(TYPE, TestName)is only suitable for very small default fixture tests; most real test files define derived fixtures.- Use
GRAPHIC_TESTSwhen multiple test functions need to be assembled into the same grid screenshot. Keep sharingSetScreenSize, and remember that the output file name does not include an individual test name. - Only use
TestCaseCapture, sleep afterFlushImplicitTransaction, or need to avoid automatic screenshots, useGRAPHIC_N_TEST。 - Unless the task explicitly involves recording/playback, do not use
GRAPHIC_D_TEST. The current test corpus mainly uses automatic and manual tests.
3. Build the fixture
Most files use this structure:
class ExampleTest : public RSGraphicTest {
public:
void BeforeEach() override
{
SetScreenSize(screenWidth, screenHeight);
}
private:
const int screenWidth = 1200;
const int screenHeight = 2000;
};
Only use SetSurfaceBoundswhen the test deliberately captures a sub-region or full-screen display behavior. For special display screenshots, sub-windows, and manual screenshots, refer to existing files in the same feature area.
4. Create visible and deterministic pixel output
Pixel comparison tests need clear, stable visuals:
- Unless testing clipping or out-of-bounds behavior, place nodes within the configured screen range.
- Use a grid layout for parameter matrices: based on
screenWidth、screenHeight, rows and columns, calculatesizeX、sizeY、x、y。 - Use highly contrasting backgrounds, borders, and image content so expected differences are visible.
- When testing property clamping, cover boundary values: negative numbers, 0, intermediate values, 1, large values, invalid enum values, etc.
- If each value should generate an independent image, use multiple
GRAPHIC_TEST; if values should be compared in the same screenshot, use a grid within a single test.
5. Correctly add and keep nodes alive
Every node added to the scene and requiring rendering should be handled like this:
GetRootNode()->AddChild(testNode);
RegisterNode(testNode);
For parent-child node trees, if the local variables of the parent or child node may go out of scope, both parent and child must be registered. For sub-windows, add via GetRootNode()->AddChildToSubWindow(subId, node) , and still call RegisterNode(node)。
6. Only flush when necessary
Automatic tests usually rely on TearDown() for unified flush and screenshot. Add RSTransactionProxy::GetInstance()->FlushImplicitTransaction()。
When using FlushImplicitTransaction , you need to include transaction/rs_interfaces.h。
7. Update BUILD.gn when adding files
When adding .cpp , you must update graphic_test/test/BUILD.gn, inserting the relative path into the matching sources array, for example rs_display_effect_sources、rs_effect_feature_sources、open_capability_sources、rs_func_feature_sources、rs_perform_feature_sources、rs_framework_sources or effect_kit_sources。
Ordinary graphic tests should not create new ohos_unittest target. Existing RSGraphicTest target already aggregates the sources arrays of each category.
Necessary checks before completion
Before claiming completion, at minimum run a quick text check:
rg -n "GRAPHIC_(N_)?TESTS?|RegisterNode|FlushImplicitTransaction" path/to/new_or_changed.cpp
rg -n "relative/path/to/new_file.cpp" graphic_test/test/BUILD.gn
Then confirm:
- The file has an Apache copyright header consistent with adjacent tests.
- Includes match actual API usage, with no leftover template junk.
- The code is located in
namespace OHOS::Rosen。 - Each test macro uses the correct fixture, type, and a unique test name.
- Every scene node that needs rendering has been added to the root or sub-window, and
RegisterNode。 - Manual screenshot tests call the screenshot helper after flush/wait, and use
GRAPHIC_N_TEST。 - The new file has been added to the correct source array.
- There are no leftover placeholder calls, such as
DrawTextBlob(...)、paintSetColoror fabricated helper names.
Common failure modes
| Failure symptom | Cause | Fix |
|---|---|---|
| Screenshot is blank | Node not added, not registered, or has no visible properties | Add the child, call RegisterNode, set visible bounds/color/image |
| Drawing code fails to compile | Used a generalized Drawing API signature that does not match the local style | Look at adjacent Drawing tests, use Brush/Pen and AttachBrush/DetachBrush |
| Test is not included in the build | New .cpp not added to test/BUILD.gn category array |
Add the relative path to the correct sources list |
| Output grouping is wrong | Standalone case mistakenly used GRAPHIC_TESTS |
Unless grid aggregation is explicitly needed, use GRAPHIC_TEST |
| Race condition in special queries before automatic screenshot | Transaction not committed before querying render output | Add FlushImplicitTransaction, and refer to the wait pattern of adjacent tests |
| Tests that depend on resources render empty | Image path missing on device | Reuse an existing /data/local/tmp/... path in the same directory, or generate PixelMap data in code |
Characteristics of the current corpus
Currently graphic_test/test is mainly GRAPHIC_TEST automatic screenshots;GRAPHIC_N_TEST is heavily used for dirty regions, surface, screen, watermark, and manual screenshot flows.GRAPHIC_TESTS mainly appears in test_template style grid aggregation scenarios, and should be chosen carefully.
Most visual property tests do not assert pixel values in C++; instead they create deterministic rendering scenes, and the framework saves the PNG to /data/local/graphic_test/... before comparison.