Is it possible to test “internal” class from a c++ dll using MSTest?

前端 未结 3 937
遥遥无期
遥遥无期 2021-02-08 21:52

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

相关标签:
3条回答
  • 2021-02-08 22:25

    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:

    • export it with dllexport, or
    • write your unit test code as part of the dll itself.
    0 讨论(0)
  • 2021-02-08 22:27

    See also question: Unit testing non-exported classes in a DLL

    The three options seem to be:

    • Put the test code within the DLL, so that it has access to the non-exported classes and functions
    • Add all files containing test code to the test project, so that they are compiled twice (don't know whether this applies to MSTEst, but it would be how you would do it using something like Boost test, or CPPunit)
    • Build all of the non-exported testable code into a static library which is then linked to the test code, and to the DLL.

    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.

    0 讨论(0)
  • 2021-02-08 22:43

    Well don't shoot the messenger.

    • Visual Studio Unit testing (aka tests that run with MSTest.exe) only test managed code. You can't test unmanaged C++. There is a new native unit testing framework coming with VS11 (the next version).
    • InternalsVisibleTo like you said also applies only to managed code.
    • IMHO You usually don't need to test internal classes. Just like private types or methods, you test them via the public/exposed methods that use them. So if PublicA.Method1() is the way your clients would exercise InternalHelper.Method2() ; then I rely on the test for PublicA.Method1() to tell me if either of them is broken.
    • If you must test internal classes, try making them public (if methods are sufficient complex.. see MethodObject refactoring). Or you could make the test classes a friend of the internal classes.

    .

    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.

    0 讨论(0)
提交回复
热议问题