We are currently trying to add unit testing to our c++ application. The application is made of 30 projects that generate 29 dll and 1 exe. We use MSTest to run our unit test sin
There is no way, whether you're a unit testing framework or something else, to test code that you can't see. A DLL on Windows only exports symbols which have __declspec(dllexport)
defined. Any other symbol is treated as internal when the DLL is compiled, and won't be visible to code using the DLL.
This is important because it means that the linker can optimize, modify or remove code that isn't exported. The code you want to test might not be there at all. It might be there, but in a different form than you expect. The DLL is compiled under a contract that anything declared with dllexport
must be present and visible, and anything else just has to work. It doesn't have to be accessible from the outside world.
That's not a shortcoming of MSTest (even though it has plenty of other shortcomings and is a pretty awful choice for unit testing C++ code)
If you want to test that code, you have two options:
dllexport
, orSee also question: Unit testing non-exported classes in a DLL
The three options seem to be:
These all have different issues.
Putting test code into the DLL isn't ideal. Either you only include it into non-production builds, in which case you aren't testing what you release, or you include it all all builds, in which case you are shipping test code, which may be undesirable. Also there then needs to be some kind of entry point to access those tests, thus forcing the compiler to include all of the code, preventing the optimiser from removing it if it would otherwise be deemed inaccessible (it may be that some of the code you are testing cannot be accessed from any of the public methods in the DLL, so the optimiser could decide to remove them as being dead code -- having the tests in the DLL prevents that).
Adding the source files to both projects increases build time and maintenance complexity. Each time you add a new source file, or remove a source file it will need adding in both places. Also depending on the size of the code, this can increase build time considerably as it has to build a lot of the code twice.
Putting all non-exported testable code into a static library has the downside of creating an extra project in the solution, and makes the organisation more complicated. You need to be careful about the code structure (one source file should only contain exported or non-exported code for example), and it means you need separate test projects for the exported parts and for the non-exported parts. However it means that the code is only compiled once, and the tests are not part of the final executable, and the optimizer can do its full work.
Depending on the size of the public interface to the DLL, that is the number of exported classes/functions, the third option is the most workable in my opinion. Often you only have a small public interface which is a facade for a larger internal structure. Everything other than the public facade can go into a separate static library, which can then easily be linked to the test executable and to the DLL.
Well don't shoot the messenger.
.
class ProductionSUT
{
// production code to be tested
friend class TestProductSUT;
}
Disclaimer: Haven't tried this out.. so may need some tweaks to pacify the compiler.