问题
I am taking over a project that exposes components via ATL.
I see two major areas for the unit test to cover with this setup:
- Testing the internal components (may or may not be exposed via COM)
- Testing the external exposed components (aka testing the exposed interface)
Currently the project has all of its internal components unit tests inside of the solution. They are enabled by a preprocessor flag that compiles it in and executes when you run.
From the research I have been doing, it appears that the "norm" is to place the unit testing in a different sub project and to have the main solution supply hooks for the unit tests to access internal components. With this setup, the unit testing solution would set a dependency to the solution being tested. Is this truly the "norm", or are there a lot of people out there that place their unit testing framework inside of the solution that is being tested (aka unit test is not a sub project but rather loose cpps that are #ifdef
'd out if the preprocessor flag is not supplied)?
It appears that the unit testing framework currently in use is cppunit and I was thinking of switching it over to gtest and trying to move everything into a different sub project but I want to make sure the effort will be worth it in the long run.
One way I thought of was to __declspec
the classes to be tested and they are only exposed when the preprocessor define is specified. Then the separate unit test sub project would enable that preprocessor to tell the main solution to expose the inners. I am just not sure if this is the best route.
So my questions are:
- Is the norm to place unit tests in a separate (sub)project and expose the components from the source that will be tested (either via hooks, exposing the class definition, etc)?
- What is the best way to expose the internal components from a COM DLL?
- Would a preprocessor flag that enables
__declspec
for the internal components to be tested a bad idea? Has anyone else done this with their unit tests where the item being tested is not normally exposed during normal operation?
Thanks for the comments!
回答1:
Someone on another team said that their team placed all of the unit tests in separate projects and were able to expose the internals via static libs. This makes a lot of sense to me in that it helps with modularity and provides alot of other benefits. So each major coupling of code would be a static lib (without going too overboard ;) ) and for each static lib, you would have a separate unit test solution. Then your main DLL becomes a thin wrapper that exposes the necessary items.
So the solution would look like:
MainSolution
- ProjCommonLib
- ProjExportsLib
- ProjImportsLib
- ProjOtherStuffLib
- COMDLL-Proj
- UnitTestsFolder
- ProjCommonLibTests
- ProjExportsLibTests
- ProjImportsLibTests
- ProjOtherStuffLibTests
- COMDLL-ProjTests
This type of setup allows the unit tests to set dependencies on the static lib and have full access to the internals without ever having to deal with __declspec. This seems a lot cleaner because the DLL doesn't have any performance hit with the modularity because the other libraries are just that, static libraries.
I am placing this as an "answer" to see if it gets any up votes (aka, "this answer is a good approach and is what I do as well"). If this is a bad solution please post your answers.
回答2:
I would say you have a free choice over whether to embed the tests within the existing projects or to create a new one. I opt for the former approach with my cppunit tests as it means that you don't need to create new projects, but with C# projects I use Visual Studio's unit testing framework which does the grunt-work of creating and maintaining a separate project.
I have never had any problems with my #ifdef
'ed blocks not recompiling -- the dependency checking sees to that (if you exposed them in a separate dll then used exports then this would be a problem.
I've been using cppunit
for a good number of years and I've only very recently used gtest
. I would say that while gtest is very rich in features, there are quite a number of structural differences that would make it a big job to port. If the existing tests are in cppunit then I'd suggest continuing with that.
One thing I like about cppunit which (as far as I've been able to find) isn't supported in gtest is that the first failure within a fixture causes the fixture to fail, so you can do this:
CPPUNIT_ASSERT(pointer!=NULL);
CPPUNIT_ASSERT(pointer->deferenceIt()); // if the pointer was null it would have returned above
gtest will continue running in this instance and crash on the second line. If the cppunit tests rely on this behaviour then this will make it even more difficult to port.
回答3:
Using #ifdef
blocks may not trigger recompilation, for that reason I believe putting unit tests in another project are a better option.
来源:https://stackoverflow.com/questions/7390171/where-do-i-place-the-unit-testing-source-and-expose-the-internal-components