0

We have legacy code that has unit tests (wohooo :D [is it then still legacy?:D]).

The production code is an exe file, another one is a DLL but with only one single entry point exported (for some plugin interface).

Then there are separate unit test projects which need to test the exe and the plugin dll. The current approach is very simple: Include the sources for the executable in the test project and test the code. Same thing for the dll file.

This has massive drawbacks: The code has to be compiled multiple times. Changing a file in the exe triggers a build for the test too. I assume the way it was done was because we were all young and clueless.

AFAIK there is no proper way to exercise the executable code (beside calling the executable and observe its effects) and it was not possible to test the DLL only via the exported functions. We did not want to spam the DLL code nor the exe with lots of __declspecs to export and import data just for the test. (Please: This discussion should not be about the fact that we should only test the DLLs public interface, this topic is more complicated).

I am now getting creative with that because compilation time is critical for us and we do not want to create a separate configuration for the exe and dll file which produces a static library as this will be still compilation overhead.

One approach I've done was for the test project to have a pre-build step that does some dirty trick: It gathers all existing obj files and links them into an impromptu static lib which is consumed by the test project. This works very well but still has some drawbacks: The pre-build step is executed always, so even if no obj file has changed, the linking of obj files has to be executed every time I build the test project -> annoying.

Now I remember that I've toyed around with adding the intermediate obj files directly to my test project but dropped this approach.

Adding the obj files has one advantage: Speed, I add the obj files I need from the project, if I do not test everything I do not need to link all obj files. But this has some major drawback: I need to manually include all those required obj files. If the exe gets another .cpp file which results in an obj it might break the test code compilation (when somebody needs this new obj file).

I would really value some different point of view on this topic.

I actually like the impromptu static lib generation very much but have to check whether I can use some msbuild facility to detect changed files to avoid creating this file every time.

1 Answer 1

2

If the tests use different compile flags/defines than the production code (not recommended, but sometimes needed), then you are out of luck and you actually need to build the sources separately for test and production uses.

If the tests use the same build configuration as the production code, then the best solution is to have 5 (or more) projects:

  • 1 project with all the code for the executable, except the function main, which produces a static library
  • 1 project with all the code for the DLL, except the function DLLmain, which produces a static library. If a static library can't contain functions that are marked as DLL-export, then you should un-mark them.
  • 1 project that builds the executable. This project only contains 1 source file for the main function and links to the static library for the actual functionality.
  • 1 project that builds the DLL. This project only contains 1 source file for the DLLmain function (and optionally DLL-export wrappers around the functions that should be exported) and links to the static library for the actual functionality.
  • 1 or more projects for the tests, which link to the libraries to access the code-under-test.

This way, each source file gets compiled only once and you only have to update one project if a file gets added/renamed/deleted.

1
  • Valid approach to that problem. What I don't like here is the amount of necessary proxy projects which wraps all those static libs into actual binaries.
    – Samuel
    May 24, 2017 at 10:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.