I want to test a Delphi application with Coded UI Tests, but I have some problems. I want access to some elements in the UI but cannot access all elements.
There is a list on the screen with some rows (according to the search parameters) and I want to access these rows to check the consistency of the values. But with the cross of Coded UI Test Builder I cannot access the rows on the application. How do I access the rows?
I just found one solution for now: Develop an extension for Coded UI Tests to interact properly with my Delphi application like the sample on the Microsoft Web site. It's an extension for Excel that allow you to access each cell. But it sounds difficult and the application I have to test is really complex as well.
If your interface is plain VCL, you can access most components by using their underneath HWND handle. It will work for TEdit TMemo TComboBox TCheckBox and so one. But some graphics components won't be able to be accessible from GDI messages, e.g. TLabel or TGrid.
So I guess you'll have to use a Delphi plug-in in your application, to let accessible the VCL components level. Use the ComponentCount + Components[] properties of a TForm (via recursive call) to access your component to be tested. Then publish its properties to the Coded UI Tests extension, which is to be written.
I speak about a "plug-in" here, because I do not think we may easily have access to all classes to be monitored / modified. Some "plug-in" architecture may help an application to work as usual, or in "Coded UI Tests mode", during testing phase. Perhaps better that a separated compilation for the purpose of tests: you should better test the final compiled executable. If you want only unit testing, you may recompile, stub and mock your application to only test a given form. But you'll need to code the form to be easily unit-tested (using dependency injection or such), which is far from easy in the default Delphi world (as with other RAD approaches).
Could be interesting to initiate an Open Source project (included with DUnit?) to develop such a platform. Or use an existing UI test framework for Delphi as base. A lot of companies we work in are mixing .Net and Delphi technologies, and would benefit for such a tool.
Related
We converted a large application suite from another database layer to FireDAC. The (Win32) programs currently do not implement a FDGuixWaitCursor, and the legacy code has calls to 'push', change and 'pop' the screen cursor.
Should I add FDGuixWaitCursor to my 'base' datamodule for any important/technical reason?
The documentation Preparing a FireDAC Application for Run Time does not really answer that.
Not necessarily. The TFDGUIxWaitCursor component makes sense to use if you wanted to setup the cursor, handle cursor changing events or include the project type implementation by setting up the Provider property. Nothing more at this time (Delphi 10.2.3 Tokyo).
If you don't need any of this, you can just include FireDAC.VCLUI.Wait module into a VCL project, FireDAC.FMXUI.Wait into an FMX project, or FireDAC.ConsoleUI.Wait into a console project.
It's worth adding that FireDAC includes all the necessary modules automatically for its design time created components (so one of them is most likely included in your data module).
I trying to implement some basic automated testing on a 10 million LOC project that don't follow good OO pratices (ex: isolating business logic into classes/units) with the DUnit that comes along with Delphi 2010. I can't do normal unit testing on this project since each part of business logic is spread across a dozens of interdependent units, these 'groups' of units are, however, centered around certain 'main business logic screens' (ex: all invoice logic related units are centered on the main invoice screen), and since those screens are classes I can do 'main business logic screen class testing' instead of unit testing, but those 'main screens' still need a lot of stuff that is created during the process startup.
So I need to both:
Be able to run the bad project's startup stuff
Be able to access its objects
The bad project already have some exported functions that return pointers that I can cast to access it's objects, but I'm unable to call them either way:
If I create the bad project as a child process of the test process, the startup code run fine, but I can't find a way to call the exported functions without complex IPC methods or substantial change on the bad project's structure.
If I load the bad project's .exe as an dll as with the LoadLibrary function, calling any function exported by bad project's result in access violation and/or segfault errors, even this simple procedure:
procedure Test; {safecall;} {stdcall;}
begin
showmessage('Yay!');
end;
How can I do both?
The approach you're talking about (using exported functions) is not going to fly. The simplest form of communication between two Win32 programs is to have them use SendMessage or PostMessage to talk to each other. Locating the window handle (usually by window class name) is step 1, sending a message is step 2.
Secondly, DUnit gets you nowhere near your goal, and TTestCase cannot be extended neatly to be a GUI Controller as that's not what it's for. It's for unit testing. Round peg, square hole. Write TTestCases for classes you can hive off and test, and use DUnit to provide test coverage for those parts of your system that you can provide test coverage for.
For UI testing, use a completely separate framework. There are two basic approaches done by Delphi programmers for automated integration tests of the sort you're proposing.
A custom hack job. Such is what you are describing. Inside Embarcadero, there exists a framework which is called Zombie, something Nick blogged about back in 2007. Its approach is based on several kinds of "primitive IPC", usually involving a Win32 SendMessage or PostMessage window message from outside the program to a window handle of a control inside the program. However, the internal code IS SIGNIFICANTLY MODIFIED to permit zombie testing. No you can't have Teh Codez, they're internal and proprietary to Embarcadero. But it does illustrate that the approach does work, and does not require rewriting the whole application or writing a huge number of mock-classes, like unit testing
would have done. If you want to go down the hack route, you will be writing your own User Interface Testing Framework, which should probably be completely separate from and use no DUnit code. You are welcome to try, but I'm telling you, it's a serious impedance mismatch. If I was starting my own custom framework in 2013, it would be DCOM based, because Delphi DCOM server code could be simply conditionally compiled into many programs, and DCOM would handle the function call "marshalling" details for you. I suspect I would get a year into the project, and I would give up, because in the end, I doubt I could make any system (DCOM or Win32 message based) pay off.
A complete external testing tool which you write test scripts in, like AutomatedQA/SmartBear TestComplete. Your tests would not be compiled into a delphi test program, but run inside TestComplete, and Pascal-like script syntax is just one of the available options for writing your test scripts.
We have had the same problem here. It looks like you really need a delphi library project (*.dll) for the export functions to work, (I suspect no initalization of the framework takes place when calling the function directly on an executable, no warranties).
NOTE: We are still using Delphi 5, so no dunit intergration here.
The solution we've used is to adding the dunit sources to our project (the .exe project) with a conditional DEFINE, and use this conditional define in the startup unit.
Sample startup code from our application:
if ComServer.StartMode <> smAutomation then
begin
OurApplication.Login ;
end;
{$IFDEF _AS_TESTRUNNER_}
GUITestRunner.RunRegisteredTests;
{$ELSE}
if OurApplication.HasStartCommands then
begin
Application.ShowMainForm := False ;
end
else begin
if ComServer.StartMode = smAutomation then
Application.ShowMainForm := False
end;
Application.Run;
{$ENDIF}
OurApplication.Finalize;
When I use the _AS_TESTRUNNER_ conditional define, I must login first so our app (and db connections) get initialised. Followed bij the GUITestrunner of DUnit.
Testcases can be registered in the initialization part exactly as in the examples.
Works like a charm.
I'm trying to use DUnit, which came with RAD Studio XE2, to unit testing a Firemonkey app (C++).
The problem is, DUnit is a VCL project, and this makes me unable to include the Firemonkey Unit Forms (ex.: UfrmMain.h) on the testing project.
Even if I separate the Visual with Logic (MultiTier/MVC), i cannot include any Firemonkey library into my classes (sometimes this would be useful, when there is a class "CustomDatabase" which have a object of type TConnection, that is only available in Firemonkey - of course only an example).
The testing is possible when i separate the firemonkey code completely and leave it on forms, and the logic/data kept on classes with pure C++ code.
So, this "handicap" is actually a good thing? Forcing me to work with MultiTier/MVC? (This thing in C++ is new to me)
Or should i look for an alternative of unit testing, that lets me test forms too?
(Can you also recommend me some C++ project on github or code example which is separated in the mentioned way, where i can rely on?)
One possible approach would be to use TextTestRunner rather than GUITestRunner. I've never actually tried this but I think it quite plausible that TextTestRunner does not use any VCL units, or at the very least what it does use can easily be excised. And indeed a quick scan of the source code suggests that this will work.
Is it good idea to put Forms that have complete functionality in dll.
And main app will invoke dll function that returns form object.
The accepted way to do this in Delphi is to use packages rather than DLLs.
Packages are essentially DLLs but with Delphi specific capabilities that allow VCL objects to be used across package boundaries.
Trying to do this with DLLs will lead to a variety of problems that packages deal with. One downside of packages is that all modules must be compiled with the same version of Delphi. But if you are wanting to share objects across module boundaries then you would face the same restriction if you used DLLs.
The Delphi documentation has extensive coverage of packages.
Having said all that, I would add that if you can put all your code into a single module (.exe or .dll) then it does make life a lot simpler.
Adding to the answers about using packages:
Packages can only be used if both, the main app and all dlls (plugins) are written in Delphi and are written using the same version of Delphi
DLLs can be written in any programming language that can create them and can be used by any program regardless of the programming language
So, using dlls rather than packages does make sense.
Regarding the actual question: Yes, it is possible to put forms into dlls and they usually work fine. Just make sure that you do not pass them around because they are only valid objects within the context of the dll. You will experience the odd problem with forms losing focus or coming up behind other forms. This can usually be fixed by passing a window handle from the main executable to the dll which is then used as the parent for the form.
Also note: TObject of your dll is different from TObject of your application. The same applies to other commonly used classes and variables like (Forms.)Application.
I have done it and it was a pain in the lower back but it was not impossible. The main program was written in Visual Basic 6, some modules were written in Delphi 6, others were written in Delphi 7 and Delphi 2007.
Conclusion: If you are sure you will never use something different than Delphi for your app and for your dlls (plugins) and are willing to always recompile everything when you switch Delphi versions, you should use packages. Otherwise it might be better to use regular dlls. (And are you sure you will always be the only person writing these dlls? Maybe at some time there will be a 3rd party developer for one of the dlls who does not own the Delphi version he needs.)
IMO this is sometimes a very good idea and the only way to go - for the reasons others have mentioned, I'm not a fan of packages, and am very comfortable with DLL's. I am currently adding functionality to an app written in Delphi 5 using Delphi XE - it was either use DLL's or write in D5 - of course I opted for the former: D5 app calls DLL's written in XE that contain all the latest and greatest features. (The first projects I did in Delphi were done via the old Borland Paradox - Paradox app invoked DLL's written in Delphi 1!)
But, I don't send the form or module from the DLL back to the main app - I just send the DLL module a structure containing what it needs to know to do its work, and when it's done and the DLL's form closes, it cleans up and then and returns a numerical code or structure back to caller indicating success, failure etc ( old fashioned but very effective).
Passing the form instance from the DLL back to your main app across the DLL threshhold can be problematic - note #dummzeuch's excellent answer above with some good tips on how to negotiate some of those problems should you decide that is your only solution.
+1 for everything that David Heffernan says.
Strategically, you really only need to implement forms (or other functionality) in external files if you're implementing a plug in system.
If you're going to allow plugins to be authored in any language, then DLL's are the only way to go.
If your plugin system will be restricted to developers with the same version of Delphi (same team perhaps?) then go with BPL's. The additional drawback of Delphi packages, from my perspective, is the need to deploy the VCL BPL's with your app, which are always more Mb than a single compiled module.
If on the other hand you want to write a modular system, you can still do that by implementing loose coupling & "plugin" techniques within your code and still compile to a single module.
If you put a form in a normal dll the form won't be able to intercept the TAB or arrow keys. I have been told that this is due to the OnKeyDown not be passed through.
I am looking to add the capability for users to write plugins to the program I have developed in Delphi. The program is a single executable with no DLLs used.
This would allow the user community to write extensions to my program to access the internal data and add capabilities that they may find useful.
I've seen the post at: Suggestions for Adding Plugin Capability? but its answers don't seem transferrable to a Delphi program.
I would like, if possible, to add this capability and keep my application as a single executable without any DLLs or additional modules required.
Do you know of any resources, components or articles that would suggest how to best do this in Delphi, or do you have your own recommendation?
The first question I would ask is, do you need the plugins to access the UI of your host application, or add any UI elements of their own? Or will the plugins be limited to querying and/or supplying data to your host app?
The latter is much easier and opens up two possibilities. Others have already mentioned DLLs, which is the first way to go. Certain caveats apply - in general you should be interfacing with a dll using only the data types that are used in Windows API. THat way you can be sure that the plugin DLLs will understand your data types, no matter what language/compiler they were created in. (So for example, use PChars, not strings. Do not as a rule pass Delphi classes such as TStream to a DLL. This will appear to work in some cases, but is unsafe in general, because even if the DLL was compiled in Delphi, it may have been a different version of the compiler, with a slightly different idea of what TStream is). Google for using DLLs in Delphi, and you'll find plenty more tips.
Another way that hasn't been mentioned yet is to enable scripting in your application itself. There are several very capable 3rd-party scripting engines, both commercial and free, and most of them allow you to exchange Delphi objects with the script. Some of these libraries support only Pascal as the scripting language, others will let you use Basic (perhaps better for beginner users) or other languages. See for example RemObjects Pascal Script (free) at http://www.remobjects.com/free.aspx .
My favorite scripting solution at the moment is Python for Delphi (P4D, also free) from http://mmm-experts.com/Products.aspx?ProductID=3 It can interface beautifully with your classes via RTTI, and allows you to execute Python code in your Delphi app, as well as use Delphi classes in Python scripts. Given the popularity of Python, this may be a viable solution if you want to attract developers to your project. However, every user will need to have a Python distribution installed.
It seems to me that the barrier to entry, from the point of view of potential plugin writers, is lower if you use scripting than if you choose DLLs.
Now, back to my initial question: things get much more complicated if you need the plugins to interact with your user interface, e.g. by placing controls on it. In general, DLLs cannot be used to do this. The Borland/CodeGear-sanctioned way is to use packages (BPLs). With BPLs, you can access and instantiate classes offered by a plugin as if they were declared in your host application. The catch is, all BPLs must be compiled with the same exact version and build of Delphi that your main application is. In my opinion this makes packages completely impractical, since it's hard to expect that all the potential plugin writers around the world will be using the same version of Delphi you are. A major pitfall.
To get around this, I have experimented with a different approach: keep using DLLs, and develop a syntax for the plugin to describe the UI it needs, then create the UI yourself in the host app. (XML is a convenient way to express the UI, since you get the concept of parenting / nesting for free.) The UI description syntax can include callbacks to the DLL triggered when the contents or state of the control changes. This method will restrict plugins to the set of VCL controls your application already uses or has registered, though. And it's not a one-nighter job, while BPLs certainly are.
Google for "Delphi plugin framework", too. There are some ready-made solutions, but as far as I know they usually use BPLs, with their limited usefulness.
Actually, the accepted answer to the question you cite is quite appropriate for Delphi as well. Your plug-ins will be DLLs, and you can dictate that they should export a function with a certain name and signature. Then, your program will load the DLL (with LoadLibrary) and get the address of the function (with GetProcAddress). If the DLL doesn't load, or the function isn't there, then the DLL is not a plug-in for your application.
After you have the address for the DLL, you can call it. You can pass the function an interface to something that represents the parts of your application that you wish to expose. You can also require that the function return an interface with methods that your application will call at various times.
When testing your plug-in system, it will be wise to write a plug-in yourself with a language other than Delphi. That way, you can be more confident that you haven't inadvertently required everyone to use Delphi.
At first I went for BPL and DLL base plugins. And found them hard to mantain.
If you use BPL system, then you need to match BPL version with EXE version. This includes Delphi updates which can break something. I found out (the hard way) that if I need to include all my plugins with every release, there is no point in having plugins at all.
Then I switched to plain DLL plugins. But that system just complicated code base. And that's not a good thing.
While crusing the net I found out Lua embedded script language, and delivered with it. Lua is 150K DLL, embedding bytecode compiler, interpreter and very simple and smart dynamic programing language.
My plugins are simple lua scripts. Easily mantaind and made. There are premade Delphi examples, so you can export any class or procedure as Lua table or function. GUI or not. For example I had TurboPower Abbrevia in my app for zipping. I exported my zipping class to lua, and all plugins now can call zip('.', 'dir.zip') and unzip(). Then I switched to 7zip and only implemented old class to use 7zip. All plugins work as they did, with support for new zip('.', 'dir.7z').
I made TLuaAction which calls Execute(), Update(), Hint() procedure from its script.
Lua allso have it's own plugin system that makes it easy to add funcionality to it. Eg luacom make is easy to use COM automation, luainterface allows calling .net from lua.
See luaforge for more. There is Lua IDE made in Delphi, with source.
I tried to make an overview of all such options some time ago. Together with my readers/commenters we built this list:
DLL/BPL loaded from the program.
DLL/BPL loaded from a sandbox (which could be another copy of the program or a specialized "server" application and which communicates with the main program via messages/sockets/msmq/named pipes/mailslots/memory mapped files).
COM (in any of its variants).
DDE (please not).
External program that communicates via stanard input/output.
External program that communicates via files (file name is a parameter to the program).
External program that works via drop folder (useful for batch processing).
External program that communicates with windows messages/windows sockets/msmq/named pipes/mailslots/memory mapped files/database publish-subscribe.
The most universal method of adding plug-in capability is to use COM. A good book to get you started on the road is Delphi Com Programming by Eric Harmon. While it was originally written for Delphi versions 3 through 5, the books contents are still valid with the latest versions of Delphi.
Personally, I have used this technique along with active scripting to allow end user customization.
I'm using plug-ins to implement most of the functionality in the game engine I'm building. The main EXE is made up of a script engine, a plug-in manager, some basic graphics routines and not much else. I'm using TJvPluginManager from the JEDI VCL library. It's a very good manager, and it can add just about anything you want to your program. Check out the demos included with the package to see how it works. The only downside is that it adds a lot of JCL/JVCL code to your program, but that's not really an issue if you're already using other JVCL components.
If plugins will be developed in Delphi or C++ builder, use packages + interfaces. Delphi OTA is a good example for that.
If plugins will be language independent, COM is a good way to go.
Addition: If you won't use COM, u may need to provide SDKs for each language. And datatype handling between different languages can be pain(for example delphi string type). Delphi COM support is excellent, u don't need to worry about kind of details. Those are mostly impilicit with Delphi COM support. Don't try to invent the wheel again. I'm surprised why people doesn't tend to mention about it.
I found an article by Tim Sullivan:
Implementing Plug-Ins for Your Delphi Applications
You could have a look at Hydra from Remobjects. Not only will this allow you to add plugins, but also to mix win32 and .net.