C++ Unit Testing Redirecting stdout

Posted in software by Christopher R. Wirz on Mon May 22 2017



Unit tests are important when ensuring that your code is executing correctly as you will more-than-likely write future methods that call that code (if not, why write it?!). In order to ensure functional correctness, unit tests are used. Using Visual Studio 2015 or higher, MS Test libraries can be written in C++ using the /clr compiler flag.

Note: This post assumes Visual Studio 2015 Release 2 with v140 compiler.

There is unfortunately a bug that is known to the user community regarding debugging C++ unit tests. Due to this bug, you can't hit breakpoints in your unit tests to inspect parameters. Foruntately, there is a way to direct print statements to a text file.


#ifdef _MSC_VER && ((_MANAGED == 1) || (_M_CEE == 1) ) // Chceck if /clr

// don't let vs capture standard output
#ifndef NO_STDIO_REDIRECT
#define NO_STDIO_REDIRECT 
#endif

#include "stdafx.h"
// Needed for file Input/output
#include <stdio.h>
#include <stdlib.h>

using namespace System;
using namespace System::Text;
using namespace System::Collections::Generic;
using namespace Microsoft::VisualStudio::TestTools::UnitTesting;

namespace MyTestLib
{
	[TestClass]
	public ref class MyTestClass
	{
	private:
		TestContext^ testContextInstance;
	public:
		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		property TestContext^ TestContext
		{
			TestContext^ get()
			{
				return testContextInstance;
			}
			System::Void set(TestContext^ value)
			{
				testContextInstance = value;
			}
		};

		#pragma region Additional test attributes

		static FILE* stdout_capture;

		// Use ClassInitialize to run code before running the first test in the class
		[ClassInitialize()]
		static void ClassInitialize(TestContext^ testContext) {
			if ((stdout_capture = freopen(
		        "MyTestClass_outputfile.txt", "w", stdout
		    )) == NULL) {
				exit(-1);
			}
		};
		
		// Use ClassCleanup to run code after all tests in a class have run
		[ClassCleanup()]
		static void ClassCleanup() {
			stdout_capture = freopen("CON", "w", stdout);
		    fclose(stdout_capture);
		};
		
		// Use TestInitialize to run code before running each test
		[TestInitialize()]
		void TestInitialize() {};
		
		// Use TestCleanup to run code after each test has run
		[TestCleanup()]
		void TestCleanup() {};
		
		#pragma endregion 

		[TestMethod]
		void My_Unit_Test()
		{
		    // keep it simple for this example
		    int i = 1;

		    // This will write to the text file
		    printf("Testing the value of %d", i);

		    // Always evaluates true
		    Assert::AreEqual(i, 1, 0.0001);
		};
	};
}
#endif

Using the printf statement, output from the unit tests can be directed to the text file. This is also a great option if the unit tests are being run at a gated checkin. In this approach, you can still verify the output is as expected - possibly with a hash function.