ocornut / imgui_test_engine

Dear ImGui Automation Engine & Test Suite
386 stars 40 forks source link

Is it possible to use this Test engine for integration tests? #37

Open GasimGasimzada opened 7 months ago

GasimGasimzada commented 7 months ago

Does the backend or something matter for ImGui to work in this case? I want to somehow run Imgui tests using Google test but in an integration way where the real application is not running but I am calling Imgui to render the UI and then automatically clicking buttons etc and checking the results.

ocornut commented 6 months ago

I'm not sure I understand the question but the answer is probably yes.

where the real application is not running

The real application needs to be running, it's the one submitting ImGui widgets. But you may use a "headless" application, aka one with no visible rendering context.

GasimGasimzada commented 6 months ago

Basically, instead of running the full application that is very heavy in terms of all the functionality it has, I want to test each part of the application in isolation. In terms of testing strategy, instead of using E2E tests where the whole application is being run, I want to do integration tests where I mock some of the services that are not necessary for the UI (e.g Physics engine).

This is the type of test that I want to write (using GoogleTest):

// Function that I want to test
void renderEntityPanel(EntityDatabase &db, Entity entity) {
  If (Imgui::Begin("Entity panel")) {
    if (ImGui::Button("Add animator")) {
      db.set(entity, Animator{});
    }
    ImGui::End();
  }
}

TEST_F(EntityPanelTest, ClickingAddAnimatorCreatesAnimatorComponent) {
      auto imTest = IM_REGISTER_TEST(engine, "Tests", "test");
      imTest->TestFunc = [](auto *ctx) {
         ctx->SetRef("Entity panel");
         ctx->ItemClick("Add Animator");
      };

      EntityDatabase db;
      auto entity = db.create();

      ImGui::NewFrame();
      renderEntityPanel(db, entity);
      Imgui::Render();

      // I want to run the test function right here
      imTest->RunTestFunction();

      // Do I need to call `renderEntityPanel` again for the button to be registered?
      EXPECT_TRUE(db.has<Animator>(entity));
}

I have couple of questions to be able to achieve this:

  1. How can programatically run a registered test?

  2. In order to get this working, do I need to call

      ImGui::NewFrame();
      renderEntityPanel(db, entity);
      Imgui::Render();

    after the test function is run?

  3. Is there a guarantee that after a test function is run with item being clicked, if (ImGui::Button("Add animator")) condition will be true in the next frame?

mgerhardy commented 1 month ago

I'm not sure if this is the best approach - but I am doing this:

ImGuiTestEngineIO& test_io = ImGuiTestEngine_GetIO(_engine);
test_io.ConfigLogToTTY = true;

in the docking branch I don't want other windows to become visible

static void ImGui_ImplSDL2_NoShowWindow(ImGuiViewport *) {
}

[...]
ImGuiPlatformIO &platform_io = ImGui::GetPlatformIO();
platform_io.Platform_ShowWindow = ImGui_ImplSDL2_NoShowWindow;
[...]

this is not really headless - a NullBackend would most likely still be better, but for me it works to run it from the command line like this

ImGuiTestEngine_QueueTests(_engine, ImGuiTestGroup_Tests, "tests", ImGuiTestRunFlags_RunFromCommandLine);

Find most of my solution here https://github.com/vengi-voxel/vengi/blob/a2be632581a9883ab28811d9386718c390559d3f/src/modules/ui/IMGUIApp.cpp

ocornut commented 1 month ago

This made me realize that it may be worth extracting the "null viewport backend" support from shared/imgui_app.cpp into a more regular backend or file which may be used for that purpose (without requiring user app to use imgui_app.cpp which of course his our own helper).