Best Practice for Organizing Projects

The best way to run unit tests on your source code is to create a unit testing library project within the solution that holds your source code.

When using this kind of setup, it is good practice to separate out your application into two or more projects: a main project that drives the application and contains the interface elements, and one or more other projects that contain the application logic; these must be link library projects.

It is the link library projects that the unit testing library project(s) can interact with. You can have more than one unit testing library project interacting with a link library project, but it is advisable that a unit testing library project only links to one link library project. One unit testing library project testing more than one link library project is possible, but can become complicated, with output required to point to a common location for all projects.

Linking your unit testing library projects to your link library projects requires that:
  • Each test case contains a procedure pointer linking into the code under test that is located within link library project.
  • The unit testing library projects and the link library project under test share the same output directory.

In the example AirportDemo solution shown below, the AirportConsole project (a Console Application project type) is used to launch and drive the application, and contains the interface coding. This project then calls into the AirportLib project (a Link Library project type) to perform its calculations, condition tests, etc..., so together they provide a complete application. To unit test the application's logic, a separate unit testing library project (TestAirportLib) calls into the link library project (AirportLib) to ascertain the code is working as it should. You could also add additional unit testing library projects to this solution, also calling into the same link library project.

Test project organization in a Visual Studio solution

Unit testing library projects can also be self-contained: that is, the logic that they are testing resides in the same project as the test cases. However, the model described above ensures that you are testing on the very latest sources, and reduces the amount of duplicate code that may be required.

More than one unit testing library project?

If your solution contains more than one unit testing library project, you should follow these guidelines:

  • Ensure that each unit testing library project only calls into one link library project. However, you can have multiple unit testing library projects calling into the same link library project.
  • Ensure that all test program names and entry points within those programs are unique within the scope of the solution; that is, no unit testing library project contains the same named test program or entry point as any other unit testing library project within the same solution. This is because all unit test output that calls into the project containing your application logic shares the same output folder: duplicate names will cause output files to be overwritten when running multiple test cases in one test run.

Data-driven tests

If you are running multiple data-driven tests that require the same data file, you should follow these guidelines:

  • Use a separate copy of the data file for each test program, ensuring that the name of each data file is unique within the scope of the solution. Again, this is because when running multiple test cases, the files required for each test case are copied to a shared output location. If you have data files of the same name, these will be overwritten, and could be used by the wrong test cases.
  • Each data file should be an artefact located within its relevant unit testing library project, and not one externally linked.
  • Set each data file to be copied to the output directory each time the test case is run, to ensure you are always using the most up-to-date version of the file.

    Advanced properties for data file

An alternative approach to testing existing source code is to use the MFUPP preprocessor. You do not need to link into your existing source project or change any source code. You can isolate the source code to put under test by adding the source as a source link to your unit testing project. When that project has MFUPP enabled, any code insertions or stubs can be coded in the unit test project, leaving the original source code project completely untouched. This type of approach is recommended if you are focussing on smaller parts of code as the preprocessor is able to test on a more granular level than a typical unit test; see MFUPP Preprocessor for more information.