Caves Travel Diving Graphics Mizar Texts Cuisine Lemkov Contact Map RSS Polski
Trybiks' Dive Texts Testing Checking "Dangling" Event Handlers in Delphi Forms YAC Software












Rhino Mocks



UI Testing




Checking "Dangling" Event Handlers in Delphi Forms
In Automated Testing of Window Forms I wrote that various elements of the form's definition can be verified automatically. One thing to check is whether there are any event handlers defined that aren't actually hooked to the respective events (hence, called here "dangling" event handlers). For instance, that there's a FormShow procedure, but the OnShow event doesn't have a handler assigned (or has a different handler assigned).

Usually, when you define event handlers using Delphi's designer, you won't get this problem. But when using Visual Form Inheritance (VFI), moving code between classes in a hierarchy, refactoring, and performing similar operations on form classes, definitions in the form's .dfm file may get out of sync. with the actual code.

Hence the procedure below:
  procedure CheckDanglingEventHandlers(AWinControl: TWinControl);
  // Tests whether for a control named N (e.g. Form) and its event OnX (e.g. OnShow)
  // there is a procedure NX (e.g. FormShow) that is NOT defined
  // as a handler of to the OnX event.
  {$IFOPT C+ }
    LPropList: PPropList;            // list of published properties
    k, LCount: integer;
    LPropName: stirng;               // current property's name
    LExpectedHandlerName: string;    // expected name of the event handler
    LExpectedHandlerAddr: pointer;   // address of the expected event handler
    LActualHandlerInfo: TMethod;     // method info of the actual event handler
  {$ENDIF }
  {$IFOPT C+ }
    // Get the list of published properties and their count:
    LCount := GetPropList(AWinControl, LPropList);
      for k := 0 to LCount - 1 do
        // For each property:
        LPropName := LPropList[k].Name;
        if Copy(LPropName, 1, 2) = 'On' then
          // Get the expected handler name (e.g. FormShow);
          // CustomForms need to be handled a bit differently here -
          // the default name of the handler will be FormShow (for OnFormShow),
          // regardless of the form's name:
          LExpectedHandlerName := Copy(LPropName, 3, Length(LPropName));
          if AWinControl is TCustomForm then
            LExpectedHandlerName := 'Form' + LExpectedHandlerName
            LExpectedHandlerName := AWinControl.Name + LExpectedHandlerName;
          // Get the address of the default and actual event handlers:
          LExpectedHandlerAddr := AWinControl.MethodAddress(LExpectedHandlerName);
          LActualHandlerInfo := GetMethodProp(AWinControl, LPropName);
          // Either there's no method with the expected event handler name,
          // or that method's code is the same as the actual event handler's code.
          Assert((LExpectedHandlerAddr = NIL) or
            ((LExpectedHandlerAddr = LActualHandlerInfo.Code) and
             (LActualHandlerInfo.Data <> NIL)),
            AWinControl.Name + '-Event ' + LPropName + ': ' + LExpectedHandlerName);
  {$ENDIF }
This procedure should be called after a form is created.

However, this is a run-time check, so either you need to open each form in your application manually, or add unit tests that would create each form of the application automatically.

OTOH, you could write a simplified Delphi parser and a .dfm parser, and check this at the source code level... ;-)


Branko Radosevic wrote on 2015-02-11 23:20:45
What if event handler has changed default name?
Your code help me.
I need to make a parser for dfm because I intend to quickly change a lot of DFM's replace old components with new ones.


Add a comment (fields with an asterisk are required)
Name / nick *
Mail (will remain hidden) *
Your website
Comment (no tags) *
Enter the text displayed below *






Related pages

AssertWasCalled and Methods Called Multiple Times

AssertWas[Not]Called and Object Properties

Rhino Mocks's AssertWasNotCalled

Visual Studio - moving coded UI tests to a new / different project results in null reference exceptions

PrivateObject and Out/ByRef parameters

PrivateObject, WithEvents, and generics

Delphi interfaces... again

Accessing private members of base classes

PrivateObject and WithEvents

Accessing private and protected members - PrivateObject and PrivateType

VS - Test Run Error - "COM object that has been separated from its underlying RCW cannot be used"

Get the TreeViewItem for an Item in a WPF TreeView

Output in MSTest Tests (VS 2010)

Automated WPF tests and "Invalid URI: Invalid port specified."

Checking Property Change Notifications

Rhino Mocks's AssertWasCalled in VB.NET

First steps with Rhino Mocks (in VB.NET)

VS Pending Tests

Drag-n-drop files onto the application window

Intraweb and MaxConnections

A Case for FreeAndNIL

Intraweb as an Apache DSO module

"Device not supported" in Intraweb

Automated GUI Testing

Rounding and precision on the 8087 FPU

SessionTimeout in Intraweb

Using TChart with Intraweb

Unknown driver: MySQL

Automated GUI Testing in VMs

TIdMessage's CharSet

Software Guarantees

Automated Testing of Window Forms

TChart - Missing Labels in Axes

Memory Leaks and Connection Explosions in DBExpress

Controlling Conditional Defines and Compilation Switches

Detecting Memory Leaks with DUnit

last_insert_id() and DBExpress

Registering Extensions

DBExpress and Thread Safety

Forms as Frames

Checking Dangling Pointers vs. the New Memory Manager

Accessing Protected Members

Objects, interfaces, and memory management in Delphi