Skip to content
omar edited this page Sep 6, 2022 · 7 revisions

Index


Once the Test Engine is setup, most interactions are done via the ImGuiTextContext interface. Refer to imgui_te_context.h for API and comments.

You may refer to app_minimal_tests.cpp as a reference for basic tests. You may refer to our test suite imgui_tests/ for a larger amount of reference code. Please note that our test suite is written primarily with the intent of testing Dear ImGui, not with the intent of providing examples for using the API.

Registering Tests

Tests are registered via the IM_REGISTER_TEST() macro.

IM_REGISTER_TEST(ImGuiTestEngine* engine, const char* test_category, const char* test_name);

(This internally uses ImGuiTestEngine_RegisterTest() but we use a macro so we can record the source file/line of tests, making it convenient in the interactive UI to preview test source code. Please always use the macro!)

Registering an example test:

t = IM_REGISTER_TEST(e, "demo_tests", "test1");
t->GuiFunc = [](ImGuiTestContext* ctx) // Optionally provide a GUI function in addition to your application GUI
{
    ImGui::Begin("Test Window", NULL, ImGuiWindowFlags_NoSavedSettings);
    ImGui::Text("Hello, automation world");
    ImGui::Button("Click Me");
    if (ImGui::TreeNode("Node"))
    {
        static bool b = false;
        ImGui::Checkbox("Checkbox", &b);
        ImGui::TreePop();
    }
    ImGui::End();
};
t->TestFunc = [](ImGuiTestContext* ctx) // Generally provide a Test function which will drive the test.
{
    ctx->SetRef("Test Window");
    ctx->ItemClick("Click Me");
    ctx->ItemOpen("Node"); // Optional as ItemCheck("Node/Checkbox") can do it automatically
    ctx->ItemCheck("Node/Checkbox");
    ctx->ItemUncheck("Node/Checkbox");
};

demo_test_1

Check Macros

  • A failed check will:
    • Output an error and set the test status accordingly.
    • Optionally break in debugger (if test_io.ConfigBreakOnError is set).
    • Return from the function (unless _NORET() is used).
  • The main macro is IM_CHECK(), e.g. IM_CHECK(result == true);
  • Operator macros are preferred as they will display the VALUE of both operands in the log: IM_CHECK_EQ(), IM_CHECK_NE(), IM_CHECK_LT(), IM_CHECK_LE(), IM_CHECK_GT(), IM_CHECK_GE().
  • Add suffix _NORET e.g. IM_CHECK_NO_RET(result == true); to prevent the macro from returning from function on failure (which is the default).
  • Add suffix _RETV e.g. IM_CHECK_RETV(result == true, -1); to return a specific error is running from sub-functions.
  • Add suffix _SILENT e.g. IM_CHECK_SILENT(window != NULL); to omit appending to log on lower verbose levels (reduce spam).
  • Specialized checks for strings: IM_CHECK_STR_EQ(), IM_CHECK_STR_NE().
  • Specialized checks for floating point values: IM_CHECK_FLOAT_EQ_EPS(), IM_CHECK_FLOAT_NEAR().
t = IM_REGISTER_TEST(e, "demo_tests", "always_fail");
t->TestFunc = [](ImGuiTestContext* ctx)
{
    int value = 1;
    IM_CHECK_EQ(value, 2);
};

image

Using Shared Variables

Depending on the nature of your tests, you may want to share variables between your application or your GuiFunc and your TestFunc.

One solution is to set the void* UserData field of the structure ImGuiTest.

Another solution is the request the test engine to instantiate a custom structure during the duration of a test running:

struct TestVars { int MyInt = 42; };
t = IM_REGISTER_TEST(e, "demo_tests", "test2");
t->SetVarsDataType<TestVars2>();
t->GuiFunc = [](ImGuiTestContext* ctx)
{
    auto& vars = ctx->GetVars<TestVars>();
    ImGui::Begin("Test Window", NULL, ImGuiWindowFlags_NoSavedSettings);
    ImGui::SliderInt("Slider", &vars.MyInt, 0, 1000);
    ImGui::End();
};
t->TestFunc = [](ImGuiTestContext* ctx)
{
    auto& vars = ctx->GetVars<auto>();
    ctx->SetRef("Test Window");

    IM_CHECK_EQ(vars.MyInt, 42); // Check default value
    ctx->ItemInputValue("Slider", 123);
    IM_CHECK_EQ(vars.MyInt, 123); // Check value after our action
};

Named References

...

ImGuiTestContext API

...