Best Practice for Organizing Projects

A common way to run unit tests against your source code is to create a unit test library project within the solution that holds your source project(s), and then create program tests.

When using this kind of test, it is good practice to separate out the application you are putting under test into two or more projects (or programs): a main project (or program) that drives the application and contains the interface elements, and one or more other projects (or programs) that contain the application logic.

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

In the example AirportDemo solution shown below, the AirportConsoleApplication 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 AirportLinkLibrary 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 test library project (TestAirportLinkLibrary) calls into AirportLinkLibrary to ascertain the code is working as it should. You could also add additional unit test library projects to this solution, also calling into AirportLinkLibrary.

Test project organization in a Visual Studio solution

Unit test library projects can also be standalone: that is, the logic that they are testing resides in the same unit test library project as the test cases: this can be in the test cases themselves, or in separate COBOL programs and copybooks within the project. 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.

A third type of unit test, a self-contained test, also allows you to directly test code at its source by injecting unit tests into the program under test. This allows testing on a much more granular level, as these tests are now part of the same run unit as the source program, and thus has access to all data, sections and paragraphs in the source. The organization of such tests is more rigid: a unit test library project may only contain one test program (although, that may contain many tests), and only calls into one source. You can create further projects calling in to the same source however.

More than one unit test library project?

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

  • Ensure that each unit test library project only calls into one application project. However, you can have multiple unit test 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 test library project contains the same named test program or entry point as any other unit test 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 test 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