Introduction
Native C++ test unit frameworks are a lot, but In visual studio 2012 there is a fantastic project template called Native Unit Test and it's fully supported in the visual studio to run the tests in the test explorer.
Background
I searched for testing frameworks for native C++, as many experienced programmers said Google Test Framework or known as GTest is the best, I used it is more advanced but it shows the result in a dos window coloring the alerts.., but in this visual studio test project it is different we will use the visual studio to write and run our tests
Using the code
We will create a solution that contains three projects.
- The first is a Win32 library called DemoBusiness that will contain our business classes.
In this library I'll use the class that visual studio generated for me
CDemoBusiness
.
#ifdef DEMOBUSINESS_EXPORTS
#define DEMOBUSINESS_API __declspec(dllexport)
#else
#define DEMOBUSINESS_API __declspec(dllimport)
#endif
class CDemoBusinessTest;
class DEMOBUSINESS_API CDemoBusiness
{
private: int data;
public:
CDemoBusiness(void);
template<class T> T Max(T item1, T item2) const
{
if (item2 > item1)
{
return item2;
}
return item1;
}
void SetData(int data);
int GetData() const;
int BadAdd(int num1, int num2) const;
int ThrowingException() const;
const int* ReturnNullData() const;
const int* ReturnData() const;
friend class CDemoBusinessTest;
};
#include "stdafx.h"
#include "DemoBusiness.h"
CDemoBusiness::CDemoBusiness() : data(0)
{
return;
}
void CDemoBusiness::SetData( int data )
{
this->data = data;
}
int CDemoBusiness::GetData() const
{
return this->data;
}
int CDemoBusiness::BadAdd( int num1, int num2 ) const
{
return num1 + num2 + 10;
}
int CDemoBusiness::ThrowingException() const
{
throw exception("Problem");
return 0;
}
const int* CDemoBusiness::ReturnNullData() const
{
return nullptr;
}
const int* CDemoBusiness::ReturnData() const
{
return &data;
}
- The second project is the native unit test project to test the previous business project.
Create it from File -> New -> Project -> c++ -> Test -> Native Unit Test.
Add the dependency to the DemoBusiness project. add the output DemoBusiness.lib to the linker input and add its output directory to the libraries directory in
C++ directories, make sure they have the same output directory if it is shared linking not static linking, it is recommended to use static linking.
Delete the default unittest1.cpp file and add a new cpp file for the test, I have created the following test for our class:
#include "stdafx.h"
#include "../DemoBusiness/DemoBusiness.h"//this is the file containing the code to test
#include <CppUnitTest.h>
#include <exception>
using namespace std;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
BEGIN_TEST_MODULE_ATTRIBUTE()
TEST_MODULE_ATTRIBUTE(L"Project", L"DemoBusiness")
TEST_MODULE_ATTRIBUTE(L"Owner", L"Ahmed")
TEST_MODULE_ATTRIBUTE(L"Date", L"22/10/2013")
END_TEST_MODULE_ATTRIBUTE()
TEST_MODULE_INITIALIZE(ModuleStartup)
{
Logger::WriteMessage(L"The test is starting....");
}
TEST_MODULE_CLEANUP(ModuleFinalize)
{
Logger::WriteMessage(L"Finalizing the test.");
}
TEST_CLASS(CDemoBusinessTest)
{
public:
CDemoBusinessTest()
{
Logger::WriteMessage(L"Inside the CDemoBusinessTest");
}
BEGIN_TEST_CLASS_ATTRIBUTE()
TEST_CLASS_ATTRIBUTE(L"Owner", L"Ahmed")
TEST_CLASS_ATTRIBUTE(L"Descrioption", L"CDemoBusiness")
TEST_CLASS_ATTRIBUTE(L"Priority", L"Critical")
END_TEST_CLASS_ATTRIBUTE()
TEST_CLASS_INITIALIZE(ClassInitialize)
{
Logger::WriteMessage(L"Initializing the class");
}
TEST_CLASS_CLEANUP(ClassFinalize)
{
Logger::WriteMessage(L"Finalizing the class");
}
BEGIN_TEST_METHOD_ATTRIBUTE(TestInitialData)
TEST_OWNER(L"Ahmed")
TEST_DESCRIPTION(L"Make sure that data is initialized to zero,
as data is private this testclass must be friend to our class")
END_TEST_METHOD_ATTRIBUTE()
TEST_METHOD(TestInitialData)
{
CDemoBusiness demo;
Assert::AreEqual(demo.data, 1);
}
TEST_METHOD(TestMax)
{
CDemoBusiness demo;
double d1 = 192.123;
double d2 = 192.122;
Assert::AreEqual(demo.Max(d1, d2), d1);
}
TEST_METHOD(TestDataTransfer)
{
CDemoBusiness demo;
int data = 100;
demo.SetData(data);
Assert::AreEqual(demo.GetData(), data);
}
TEST_METHOD(TestBadAdd)
{
CDemoBusiness demo;
int num1 = 10;
int num2 = 20;
int addition = num1 + num2;
Assert::AreNotEqual(demo.BadAdd(num1, num2), addition);
}
TEST_METHOD(TestThrowingException)
{
CDemoBusiness demo;
Assert::ExpectException<exception>([&]
{
demo.ThrowingException();
});
}
TEST_METHOD(TestReturnNullData)
{
CDemoBusiness demo;
Assert::IsNull(demo.ReturnNullData());
}
TEST_METHOD(TestReturnData)
{
CDemoBusiness demo;
Assert::IsNotNull(demo.ReturnData());
}
TEST_METHOD(AreSameTest)
{
int x = 100;
int& y = x;
Assert::AreSame(x, y);
}
};
- The optional main application that will uses the business classes// in our case it is optional as we are discovering the native testing feature in VS2012.
- *After adding any new logic to the DemoBusiness project go to the test and add your test method
- *After any changes in the DemoBusiness build it then build the test module and run all the tests from the test explorer
- *All the
Logger::<span style="color: black; font-family: Consolas, "Courier New", Courier, mono; font-size: 9pt; white-space: pre; background-color: rgb(251, 237, 187);">WriteMessage(L"")</span>
the notes will appear in the output window but select
Tests in show output from.
Points of Interest
For more information about native unit testing:
- Using Microsoft.VisualStudio.TestTools.CppUnitTestFramework:
http://msdn.microsoft.com/en-us/library/hh694604.aspx
- Using Assert::ExpectException with Native Unit Testing in VS11:
http://blogs.msdn.com/b/dgartner/archive/2012/04/22/using-assert-expectexception-with-native-unit-testing-in-vs11.aspx
- Running Unit Tests with Test Explorer:
http://msdn.microsoft.com/en-us/library/hh270865.aspx
This is the output of the testing: