Question

I'm trying to run a GUI unit test with DUnit to an application whose mainform creates dynamically frames to itself. I've been able to create the application-to-test's mainform as a form in the test case and access its menu items etc.

The problem comes when the application tries to create a frame dynamically. The frame's resource reading comes to a point where it needs the window handle (in my case, setting the caption of a tab sheet). Here it goes from TWinControl.GetHandle to TWinControl.CreateWnd and to TCustomFrame.CreateParams.

In this CreateParams, the code says:

  if Parent = nil then
    Params.WndParent := Application.Handle;

This is where the difference occurs. When I run the actual application (not in the test), the Application.Handle here returns a non-zero number and the flow continues ok. But in the DUnit test application, the Application.Handle here returns 0. This causes the code in the TWinControl.CreateWnd to raise an exception telling that the frame does not have a parent:

  with Params do
  begin
    if (WndParent = 0) and (Style and WS_CHILD <> 0) then
      if (Owner <> nil) and (csReading in Owner.ComponentState) and
        (Owner is TWinControl) then
        WndParent := TWinControl(Owner).Handle
      else
        raise EInvalidOperation.CreateFmt(SParentRequired, [Name]);

I'd like to try to get around this problem (and in general, all test problems) without modifying the "production" code just because of the tests. Can you provide any clues on whether I could somehow force the "Application" to something else, or in some other way work around this?

Looking at the code, a possible other workaround scenario might be to try to get the owner (which is my "MainForm" of the application-to-test, i.e. whose handle I'd want to get) to be in csReading state while doing this frame creation in the test, but at least initially it doesn't seem so straightforward to get this to happen either.

Was it helpful?

Solution 2

Thanks for all the comments and replies! I believe to have solved the issues, at least ones found out so far. I'll summarize my findings and final situation below (in case someone else would find any of this useful).

I have a test decorator class inheriting from TTestSetup, which holds a reference to a dummy (main) form that it creates when necessary.

I also found a way to switch the Application.MainForm on runtime using approach like this: http://www.swissdelphicenter.ch/torry/showcode.php?id=665

In the test decorator SetUp method I create first the dummy form and then set it as the main form of the Application (this setting might not be necessary here).

Then I have a test case class (inheriting from TGUITestCase), whose SetUp and TearDown are run for each test. In this SetUp I create the mainform that I'm testing and then set it as the Application's main form. Then after the test in the test case's TearDown, I set the dummy form again to be the main form of the Application, and only after this call Close and Free to the mainform that I'm testing. Otherwise freeing a form that is currently the Application.MainForm would cause the entire DUnit application to terminate.

OTHER TIPS

Instead of working around a way to set Application.Handle, you should create a TForm, and set your frame.parent to be that TForm.

//Dunit Test Scaffolding code...Set up a workable environment for the test:
aForm := TForm.Create(nil);
aFrame := TFrame.Create(aForm);
aFrame.Parent := aForm;

In real apps, frames will have a parent (be parented to a window, a TForm or TPanel usually). You are trying to tell a frame to run without a parent, which TFrame is not designed to do.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top