Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 since it's already included in Visual Studio 2010.

It works great for class that are declared "public". These class have this at the beginning:

#ifdef RESEAU_IMPL
    #define CLASS_DECL      _declspec(dllexport)
#else
    #define CLASS_DECL      _declspec(dllimport)
#endif 

But for all the other class (90% of the code), they are not declared public so we can't use them in our test.

I've read on google about the InternalVisibleTo attribute but it seems to be only working with c# .NET assembly. Am I right? I also read to declare my class "as_friend" but I'm not sure where to put this.

So in brief: I want to test class that are not exported/public in the DLL. How do I do that?

Thanks

* EDIT *

Gishu commented that Unit Testing was not possible in unmanaged code but it is possible. See, this is a TestMethode that test native c++ code. CVersion is in C++ MFC.

[TestMethod]
void AssignationCVersion()
{
    CVersion version1234(1,2,3,4);
    CVersion version4321(4,3,2,1);
    Assert::IsTrue(version1234 != version4321);
    version1234 = version4321;
    Assert::IsTrue(version1234 == version4321);
};

But what seems to be impossible is to use special tag to test internal function.I'm the first to agree that testing internal method is not good practice but these DLL are not utility functions but are part of the "real" application (maybe it's bad design but it was done 15 years ago). Anyone has an idea on the subject?

like image 853
Jean-François Côté Avatar asked Oct 13 '11 20:10

Jean-François Côté


People also ask

Does MSTest work with .NET core?

In this article, I will explain about the unit test in asp.net core using MSTest. There are three different test frameworks which are supported by the unit test with asp.net core: MSTest, xUnit, and NUnit, which allow us to test our code in a consistent way.

How do I test a class in Visual Studio?

Run tests in Test Explorer If Test Explorer is not visible, choose Test on the Visual Studio menu, choose Windows, and then choose Test Explorer (or press Ctrl + E, T). As you run, write, and rerun your tests, the Test Explorer displays the results in a default grouping of Project, Namespace, and Class.


2 Answers

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.

like image 133
Tom Quarendon Avatar answered Sep 28 '22 15:09

Tom Quarendon


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.
like image 44
jalf Avatar answered Sep 28 '22 14:09

jalf