Organization of UnitTests in a existing library ProjectGroup - delphi

In our Delphi2007 environment we have a SGLibrary groupproj which contains some 30 bpls. We're just starting out creating unittests for these libraries and are not sure what the most convenient way of organizing the Unittest projects would be.
We are inclined to create a test-executable for each bpl, as this will make compilation an running easy and fast. The test-exe can be set as the active project and Compilation of the bpl can be forced by setting a dependency. It is also easy to run tests, ie by setting the test-executable as the Hostapplication of the bpl.
But the downside is that the library groupproject will be expanded with another 30 items, making it a very large group (why can't we make subgroups in Delpi ???).
The opposite arrangement would be to create 1 test executable which contains all unit-tests but that would create a executable with over a hundred units, and lots of depencies which all have to be compiled before a single test can be run.
So my question ... Does anybody have any suggestions, best practices, or other ideas on how to organize this into a manageable and fast running setup?
Extra consideration: We want to have the possibility to run all tests at once, and of course this will be easier in we put all tests in one executable.

There is a little known feature of DUnit that supports running tests from a dll. You basically create a dunit exe project that has no tests of its own, rather it loads tests from dlls.
Each dll needs to export a single function:
library MyTests;
uses
TestFramework{, add your test units};
function Test: ITest;
begin
result := RegisteredTests;
end;
exports
Test;
end;
Then you just add test cases to the dll as normal. The tests are automatically registered in each unit's initialization section.
IMHO its a pity this isn't promoted as the standard way of working with DUnit. Most unit testing frameworks for other languages are organized this way. They provide a single test runner executable which dynamically loads test cases from any number of loadable modules.
In addition to letting you break up your tests for easier organization it also allows you to run the same tests under multiple scenarios. Perhaps you want to run your tests using different compiler options for your debug and release builds (or even different versions of the compiler) so you are more confident that the code behaves consistently. You can build multiple dlls from the same source and run them in the same session.

I'd probably do both, so you end up with this:
all your unit tests, group them by BPL.
a project for each of the units tests for each BPL.
a project with all the tests.
You can use the final project in your continuous integration system, and the former for testing things that are not yet checked in.
This is indeed a large number of projects, a price you pay for being able to improve the quality of your code.
--jeroen

Related

Dealing with shared helpers in Common Test suites?

I've got an Erlang project comprising a bunch of different applications. I'm using Common Test to do some of the testing.
apps/foo/suites/foo_SUITE.erl
apps/bar/suites/bar_SUITE.erl
I'm starting to see duplication of utility code in those suites.
Where should I put my utility code so that it can be shared between the two suites?
I've considered adding another application:
apps/test_stuff
...but I can't make the CT suites depend on this without making the application under test depend on this (or can I?). I don't want to do that, because test_stuff is only needed when testing.
I have a similar problem with my eunit tests, both between applications (apps/foo/test vs. apps/bar/test), and where I'm using similar functionality between the eunit and CT tests in the same application (apps/bar/suites vs apps/bar/test). Can I use the same solution for this case as well? Or do I need to ask another question about that?
Do you think ct:require/1,2 could help you so that foo and bar SUITE would require test_stuff before it gets executed? For more information http://www.erlang.org/doc/man/ct.html#require-1
It depends on how you are packaging your final releases. For example, I use rebar for relase management. I have Cowboy fetched along with other dependencies for testing purposes, but in my reltool.config, I omit it, so it doesn't get packaged with the final product. I use rebar to run Common Test, and it's able to add Cowboy to the path without having it bundled as a lib with everything else or added as a dependency to the app I'm testing.
However, if you have another process which infers your release configuration from your dependencies, you'll have to find a way to exclude your test code when you generate a release.

How to deal with tangled uses dependencies in order to start unit testing?

I have a messy Delphi 7 legacy system to maintain and develop. I am already reading "Working effectively with legacy code" and I like this book very much.
In order to start following the advices in the book, I created a test project and tried to write a single test. To do this I need to add some unit to the test project, but here lies the problem: the system under test has horrific uses dependencies. One unit uses some other unit, that uses some other unit and so on, and so on. It seems that most units directly or indirectly use one particular unit, and this unit in turn has 170 dependencies in its uses clause. There are indirect circular dependencies also.
Currently I am trying to add all of the legacy system's units into the test project, but I am running into all kind of problems, like "unit xxx was compiled with a different version of xxx", and others.
So I wonder if I am doing something wrong. I have used unit testing before, but in my own projects, that were smaller and with better structure and modularization. What are the options I have in this situation? Am I missing something?
You will always have dependencies in your code. Well, as long as you have code re-use, you will have dependencies. Since you are testing a legacy system, wholesale re-structuring is out of the question.
So you simply need to accept the dependencies. The most convenient and practical approach is to have a single unit tests project. That project contains all your unit tests. Use the facilities of your runner program to run only specific tests at any one time.
This leads to your project have the same list of units in its .dpr file as the main project. That's what you have currently tried and it's the right approach.
Your problem sounds like you are sharing the DCU directory (unit output directory) between the main project and the unit tests project. And you have different compiler options for the two projects. That's the most likely explanation for the error you report.
There are a couple of obvious solutions:
Align the compiler options for both projects. Then they can share DCUs.
Have separate DCU directories for the two projects.
Option 2 is much more robust and is best practise. However, you should try to understand why the compiler options differ. It's quite possible that your compiler options in the new unit tests project will need to be changed so that the units under test compile and function as desired. In modern Delphi I would use option sets to ensure consistency of compiler options.
Now, there may be other technical problems that you are facing, and my explanation of the error may not be quite right since I'm having to guess a little. But the bottom line is that having the same list of units in your .dpr files is the way to go.

Does a separate .exe always require a separate project in Delphi?

Our application requires quite a few tools and utilities we have written to support our product. Things like data converters, backup utilities etc. Currently, each of these utilities is a separate Delphi Project. On top of that, many of these projects also have a corresponding DUnit project for unit testing, which also have to be a separate project. We currently have 13 separate Delphi projects. These projects are all in one Project Group.
Is this necessary? Do we have to have so many separate projects, or is there a way in Delphi to have multiple entry points into the same project?
Also, sometimes it would be convenient during development to just write some code and 'run' it. To do this now I end up hacking the project file; commenting out the normal behaviour and replacing it with the code I want to run. Is this the only way?
We use Delphi 2010 if that makes a difference.
You can do either of these pretty easily:
Combine your projects into a project group, to be able to work with them together more easily.
(My preference) Separate your projects into different units (instead of project files), create a single application that uses all those units, and call different functionality based on command-line parameters (see ParamCount and ParamStr in the documentation) You can then easily write unit tests by testing each of the units (pun not intended) separately.
Regarding your edit: Delphi is a compiled, not interpreted, language. You can't just "run" code without compiling it, unless you can use functionality that's in your app using the Evaluate/Modify menu item during debugging. (Set a breakpoint and run your app. When it hits the breakpoint, use Ctrl+F7 to open the Evaluate/Modify dialog. Note that this has limited functionality due to the nature of the optimizer and compiler.
Organize your project in one or more Project Groups, and you could use project (exe) parameters to execute just some part of your exe.
As it was already mentioned you can convert mini projects into units. Then use compile conditionals ($ifdef etc.) to select which unit is being included in the compiled program. It would be also handy to be able to automatically switch the name of the generated executable file. I think it would be possible to create a relatively simple OTA (Open Tools API) plugin that could control all those features.
To run small parts of code you can create a separate lightweight console project where you can paste the code to the main function.

Delphi & unit testing: Include tested source in project, or just use it?

I have a project group with the main project and a test project.
When writing unit tests for a class in the main project, do you include the source file in the test project, or do you put the path to it in the search path?
Why do you do one over the other?
Are there any best practices on this?
UPDATE:
It looks like including is the preferred option, much because of the disadvantages of 'getting access' to all units in the search path vs only getting access to the units that you intend to use.
What bugs me, though, is the need to include a file in two projects all the time. I usually keep the test project as the active project, so when I need a new class, I create a new unit, that becomes a part of the test project, but store it under the main projects path. Now, I need to remember to also include it in the main project. There should be a 'create new unit, and add it to all open projects'-action....
You should probably include the units in the test project rather than rely on a search path. You will have a much better understanding of the dependencies between units, and should make any additional dependencies obvious should they occur (particularly if they are undesirable). It might also be desirable to have more than one test project if you want to make sure there is no cross dependencies between certain parts of you main application (for example if you have some shared code with another application)
I include the source as it seems to make the IDE happier WRT speed, Code Completion, etc.
If the source files have important initialization or finalization sections then it may be necessary to include them in the testing project, otherwise it is not.
In latter case do not extend the unit test project's search path too much though, rather use one output directory for dcus of the main project.

DUnit Testing in a Midas/DataSnap project

How does one setup DUnit Testing in a Midas/DataSnap project in Delphi 2006
Edit
How does one set up a Dunit Test into a TRemoteDataModule
The project wizard in Delphi 2006 does not work with TRemoteDataModule
The question doesn't entirely make sense. Unit tests are performed in a separate project, not within your DataSnap server. Generally, tests which connect to a database are integration tests rather than unit tests. What is it, exactly that you want to test? If it's utility methods within, say, a TRemoteDataModule, you should extract those out into a separate class as class methods, and test them there. You should not have to instantiate an application server to perform unit tests.
Sorry for the terse answer above, the iPad posts whenever I hit return while editing a post.
dUnit is designed to perform unit testing, and what you are trying to do is NOT unit testing.
A test is not a unit test if:
It talks to the database
It communicates across the network
It touches the file system
It can't run at the same time as any of your other unit tests
You have to do special things to your environment (such as editing config files) to run it.
It can't run in isolation
If you follow the SOLID principles (especially the single responsibility principle), using dUnit to test your class (without testing the Midas/DataSnap related logic) should be reasonably simple. And really, you shouldn't need to test the Midas/DataSnap logic.
But there are ways to perform integration and behavioural tests on Delphi applications.
Personally, I wouldn't use TestComplete because it doesn't integrate well with any sort of CI server and the tests are stored in a proprietary binary format (which makes merging differences or maintaining changes in any source control system problematic).
You could try dSpec, but I'm not sure Jody Dawkins is maintaining it any more.
I have used the AutoIt BASIC scripting language directly on some projects, and also used its .NET assembly to drive a Delphi application using NUnit and C# on another. While not perfect, the NUnit / C# solution was more elegant than anything I'd seen for performing functional / behavioural testing Delphi applications. It did take some effort to get it setup though.

Resources