Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
In my previous post, Writing Unit Tests in Visual Studio for Native C++, I described the approach I’m using to write unit tests for native C++ code by using C++/CLI, which is C++ code that runs inside the .NET runtime. Because of this “mixed” programming model, there are some techniques you may need to employ between C++ and C++/CLI code.
Class Instance Variables
The instance variables in C++/CLI classes are different from instance variables in native C++, which means you can’t mix the two blindly. For example, you can’t use native C++ classes as instance variables in your test class. The following, for example, will not compile:
public ref class MyFixture
{
MyClass m_instance;
};
You’ll get the following error message:
error C4368: cannot define 'm_instance' as a member of managed 'Tests::MyFixture': mixed types are not supported
So how do you deal with this? Instead of using a class as the type, you have to use pointers and then create/destroy the instance in the TestInitialize and TestCleanup code:
public ref class MyFixture
{
[TestInitialize]
void Initialize()
{
m_pInstance = new MyClass();
}
[TestCleanup]
void Cleanup()
{
delete m_pInstance;
}
MyClass *m_pInstance;
};
The methods marked by TestInitialize and TestCleanup run before and after each test method.
Passing a Pointer to an Instance Variable
C++/CLI instance variables have a type of interior_ptr<T> instead of the type you wrote in your code. This makes a difference if you attempt to pass either the address or a reference to this instance variable to a native C++ method or function. For example, given the class above, you might think you could write a call to one of your native methods like this:
p->SomeMethod(&m_pInstance);
Compile this and you’ll see this message:
error C2664: 'Tests::MyFixture::MyTest' : cannot convert parameter 2 from 'cli::interior_ptr<Type>' to 'MyClass **'
This error appears because .NET uses a heap—items on the heap can be moved as a result of garbage collection. In order to send a pointer to a native method/function, you need to “pin” the pointer for the duration of the call, which you can do like this:
cli::pin_ptr<MyClass *> p = &m_pInstance;
SomeMethod(static_cast<MyClass **>(p));
Once the variable p either goes out of scope, or is assigned a new value, the pointer will be free to change again.
When you’re dealing with helper methods in your test code, you can also write this type of code:
Helper(&m_pInstance);
...
void Helper(cli::interior_ptr<MyClass *> ppInstance)
{
**ppInstance = new MyClass();
}
Comments
Anonymous
March 12, 2011
A good write-up. Thanks - makes me think I should know more about cli::interior_ptr<>Anonymous
March 15, 2011
Nothing, but funny typo: naïve C++ btw: good postAnonymous
March 16, 2011
SHK, thanks. I've fixed that typo...