3
votes

I am building a dedicated project for all the unit tests of our main project, since including them in the main project would put a strain on an already huge codebase. Now all the units of the main project are referenced in the project's dpr file with their locations. When I write a testcase for a class I simply copy the classes unit reference (and the referenced units unit references) from the main project's dpr and paste it in the unit testing project.

This means that eventually I will end up with a dpr file that includes all the main projects dpr files unit references verbatim, which will be hard to maintain when the main projects dpr changes. We are talking about thousands of units here.

My Question is, can I somehow include all unit references of one project in another project? Simply having the main project compile its dcus in one directory and including this in the unit tests projects dcu search path is not sufficient because the units have initialization routines that must be executed.

3

3 Answers

2
votes

No, there's no way to do this (well), but it may not matter much. The IDE maintains the DPR, and it's incredibly finicky about how things are referenced. Techniques which works fine in other units, like include files, will not work in the DPR, reliably. They'll compile, sure, until you do something which causes the IDE to modify the DPR, at which point the DPR code may be mangled.

However, it's not strictly necessary to include every referenced file in the DPR. It's a good idea, as it seems to make the IDE happier and faster, but if the DPR only referenced your tests and the tests referenced the units from your main project, everything would still work.

2
votes

The way I would go about implementing this would be to create a program to take an existing DPR file and generate a include file that I would then use in my testing application. You can probably do most of this using a tStringlist. This project would be run PRIOR to building your test cases.

var
  OrigDpr : tStringlist;
begin
  OrigDpr := tSTringlist.create;
  OrigDpr.LoadFromFile( originalprojectname );
  while (OrigDpr.Count > 0) and (not SameText('uses',OrigDpr.Strings[0])) do
    OrigDpr.Delete(0);
  // delete the uses line.
  if (OrigDpr.Count > 0) then
    OrigDpr.Delete(0);
  while (OrigDpr.Count > 0) and 
        (not SameText('{$R *.RES}',OrigDpr.Strings[OrigDpr.Count-1]) do
    OrigDpr.Delete(OrigDpr.Count-1);
  // delete the $R reference
  if (OrigDpr.Count > 0) then
    OrigDpr.Delete(OrigDpr.Count-1);

  OrigDpr.SaveToFile( 'pathtotestproject\TESTPROJECT.INC' );
end;

Then in your test DPR, add the following code in your project uses clause. Since the uses clause include file already includes the semicolon, use the include file at the end of your normal test units.:

USES
  // test units go FIRST
  {$I pathtotestproject\TESTPROJECT.INC}

My assumption is that you are performing late/loose binding, which is why all of this is necessary in the first place (the units are not referenced other than being in the DPR). Otherwise just using any of the units would be sufficient enough to have the initialization code executed.

EDIT

Another option would be to have the first program generate a complete unit, and then use this unit in your test application. This will compile in the initialization/finalization code from all of the referenced units. Your test application then would have to use the global repository you mentioned to gain access to these objects.

An important piece here is to make sure that the test project search path includes the source directories for the other project.

0
votes

I always keep the number of references in the .dpr minimal:

  • units that have important initializations
  • units that are involved in VFI inheritance
  • units that are the automatic instantiated forms.
  • sometimes a couple of central units to quickly navigate the business code with ctrl-enter.

and always with as minimal (relative) paths as possible.

That works fine in general with only one small problem, browsing for units via file->open sometimes messes up the current working dir, and thus the "root" for the relevant paths. A workaround is to do a file->open of an unit in the basedirs.