Posts Tagged 'unit test'

How to test MFC applications using Visual Assert or cfix

Automated testing of GUI applications is tricky. It is not only tricky because testing the GUI itself is hard (despite there being good tools around), it is also tricky because GUI applications often tend to be a bit hostile towards unit testing.

One class of GUI applications for which this kind of hostility often applies is MFC applications. Although MFC allows the use of DLLs, components, etc, the framework still encourages the use of relatively monolithic architectures.

Regardless of whether this is a good or bad thing, the question is how to make unit testing MFC applications feasible and less painful.

In one of the last releases, both cfix and Visual Assert introduced the abilify to embed unit tests into executable modules. That is, the framework allows unit tests to be compiled and linked into the main application .exe file. Such an executable can then be run in two modes: On the one hand, it can be launched regularly and the existance of unit tests will largely go unnnoticed. On the other hand, the executable can be launched indirectly via cfix of Visual Assert — and in this case, the application will not have its WinMain routine run, but rather have its unit tests be executed.

Although this feature enables us to do unit testing without having to rethink or tweak the application’s architecture more than necessary, the question still in how far MFC likes this kind of testing.

At this point, a distinction has to be made on whether the unit tests make use of MFC APIs or not. Tests that only exercise internal methods will run smoothless, without further setup or precautions needed. Of course, this also holds for tests that make of of basic MFC functionality such as using classes like CString or CArray.

For test that make use of more “interesting” MFC functions, however, it is quite possible that you will observe slightly strange behavior: API calls failing, fields not having the proper value, or maybe even crashes.

An example for this is the field AFX_MODULE_STATE::m_hCurrentInstanceHandle. During a normal run, this field will hold the address of the current module. In a unit tests, however, the following assertion will fail:

CFIX_ASSERT( AfxGetModuleState()->m_hCurrentInstanceHandle != 0 );

If you think about this for a minute, this should not really come as a surprise. As described previously, Visual Assert/cfix, when attempting to run tests embedded into an executable module, will not call the applocation’s WinMain/main routine. They will ensure that all initializers (in particular: constructors of global C++ objects) are run, but calling the actual main routine is effectively skipped. Many of the MFC APIs, however, rely on quite a bit of initialization work that is performed during startup. Some of this work is conducted as part of constructors of global objects executed, a significant part of this work, however, is done in AfxWinInit.

Quoting MSDN:

This function is called by the MFC-supplied WinMain function, as part of the CWinApp initialization of a GUI-based application, to initialize MFC.

And indeed, if you look at the default MFC WinMain routine, AfxWinMain, you will see that it calls AfxWinInit.

The key to using “interesting” MFC APIs in your unit tests therefore is to make sure that AfxWinMain has been called before.

Unfortunately, there is no counterpart to AfxWinInit, so initializing MFC in a fixture’s Before or Setup routine and shutting MFC down in a After or Teardown routine is not feasible. Rather, you have to call it once per process, something that is a bit unusual for unit testing and requires a tiny bit of manual work. The easiest way to accomplish this is to a lazy initialization helper routine:

static void InitalizeMfc()
{
  static BOOL Initialized = FALSE;
  if ( ! Initialized )
  {
    CFIX_ASSERT( AfxWinInit(
      ::GetModuleHandle(NULL),
      NULL,
      ::GetCommandLine(),
      0 ) );
    Initialized = TRUE;
  }
}

…and call it from each fixture’s Setup routine:

static void SetUp()
{
  InitalizeMfc();
}

With this in place, MFC APIs will now work properly and AfxGetModuleState()->m_hCurrentInstanceHandle will contain a proper address.

With this bit of MFC background in mind, writing unit tests for MFC applications should be not much different than writing tests for any other kind of application.

One final tip: Adding unit tests to your project introduces a dependeny to cfix.dll. In your final build, you’ll want to remove (#ifdef out, for example) all your tests so this dependency will disappear. During development, however, this dependency might be a bit of a drag because there might be machines on which cfix is not available. To alleviate this situation, consider making cfix.dll a delay-load: Unless you want to run unit tests, it is then ok to miss cfix.dll on other machines.

Advertisements

cfix finished 2nd in ATI’s Automation Honors Awards, surpassed only by JUnit

Along with JUnit, JWebUnit, NUnit, and SimpleTest, cfix was one of the nominees for the Automated Testing Institute’s Automation Honors Award 2009 in the category Best Open Source Unit Automated Test Tool. A few days ago, the results were published and cfix finished second — surpassed only by JUnit, which finished 1st (No real surprise here). If you are interested, there is a video in which the results are presented.

cfix 1.5 released; adds support for EXE-embedded tests and kernel mode multi-threading

A new version of the cfix unit testing framework is now ready for download.

Unlike the previous release, which was mainly a maintenance release, cfix 1.5 adds major new features: kernel mode multithreading and EXE-based unit tests.

EXE based unit tests

As I discussed in a previous post in the context of Visual Assert/cfix studio, cfix’ restriction to DLL based unit tests has turned out to be quite a limitation for certain kinds of projects.

In cfix 1.5, this restriction has been removed: cfix now supports both, unit tests compiled and linked into DLL modules and unit tests embedded into EXE modules.

Now, when I say embeded into an EXE module, I do not mean that you may merely leave out the /LD compiler switch — it means that you may compile and link unit tests into the actual application EXE module without impacting this application’s behavior or having to change the application’s main() routine: When you run the application direcly or through the debugger, it will behave as normal (e.g. launch GUI). Once you launch it via cfix32 -exe app.exe (or cfix64 -exe app.exe, respectively), however, the application’s main() routine will not execute and instead, your embedded unit tests will run.

This may seem awkward at first — but it offers a tremendous advantage: All of the application’s code now immediately becomes testable (i.e. accessible by unit test code) without having to do complex reorganization of your build process or source tree layout (although it is still a very good idea to enhance the build process s.t. the unit tests are stripped in the RTM builds and to make cfix.dll a delayload DLL). For many projects, relying on this feature will therefore make adopting cfix and maybe even unit testing in general much easier.

In almost all regards, EXE-embedded unit tests behave the same as their DLL counterparts. They are, however, slightly less handy when it comes to debugging (unless you use Visual Assert, which will shield you from this). For this reason, and their greater flexibility in general, it should be noted though that DLL-based unit tests will remain the preferred choice.

Kernel mode multithreading

Since its first release, cfix has featured support for multi-threaded test cases. Multi-threaded test cases are tests which spawn child threads and — and this is the important point — both, the “main” thread and the child threads may trigger assertions (i.e. use CFIX_ASSERT and friends). Regardless of the thread an assertion occurs on, it will be recognized by the framework and will lead to the test case being marked as having failed. In case this sounds trivial to you, be informed that not even JUnit properly supports this :)

And while this feature has been supported for user mode tests ever since, the infrastructure for kernel mode unit tests, which was added in version 1.1, has lacked support for this feature: There was no kernel mode counterpart of CfixCreateThread and thus, only single-threaded kernel mode tests were supported.

cfix 1.5 now finally introduces CfixCreateSystemThread: CfixCreateSystemThread is basically a wrapper for PsCreateSystemThread with the added functionality of registering the child thread with cfix. Thus, all threads spawned using CfixCreateSystemThread (rather than using PsCreateSystemThread directly) are allowed to make use of assertions.

Kudos to Matt Oh for beta-testing this feature.

Minor enhacements

Another enhancement related to multi threaded tests is Auto-joining of child threads: After a test routine completes, the framework will now automatically check whether any child threads were created. If this is the case and any of these threads are still running, they will be waited on — not before all threads have terminated will the test run resume. This feature both makes writing multi-threaded tests more convenient (you do not have to wait by yourself) and safer (No more runaway child threads).

Finally, another feature worth noting is that by specifying the -td command line switch, cfix can be directed to not capture a stack backtrace when an assertion fails. Although stack backtraces are usually very helpful, the symbol loading can make their creation quite expensive. Using this switch can therefore speed up the usage of cfix.

Download/Upgrade Now

You see, there are many good reasons to upgrade your cfix installation or — in case you are not using cfix yet — to give cfix a try.

Better yet, check out the Visual Assert AddIn for Visual C++ — it is based on the new cfix 1.5 release and seamlessly integrates with Visual Studio.

Download cfix 1.5.0 Installer
Download cfix 1.5.0 source code

cfix studio Beta 2 to add support for EXE-based unit tests

N.B. cfix studio was the code name of what has become Visual Assert

The biggest shortcoming of the current cfix studio version certainly is that it requires all tests be implemented in a DLL. Conceptually, keeping test cases separated from the remaining code certainly is a good idea — and implementing tests in a DLL is a way to accomplish this. However, there are many projects in which such separation is either not feasible or just too much effort.

The good news is that with Beta 2, this will finally change: EXEs become first class-citizens in cfix studio and it will not matter any more whether your tests are part of a DLL or EXE project — you can just put them where you think is appropriate.

Take a classic MFC/GUI application project as an example: It is pretty common for these kinds of projects that most, if not all, application logic is part of a single Visual Studio project that compiles into a single EXE. There may be some additional DLLs or LIBs, but by and large, the EXE itself is where most of the interesting things happen.

The upcoming Beta 2 release now allows you to implement all your unit tests as part of the same EXE project. This means that your tests have access to all classes, functions and resources that are part of the project — all of which you would not easily have access to if you implemented the tests in a separate DLL.

Of course, embedding unit tests into an executable raises two questions:

  1. How to strip the tests from the final release?
  2. How on earth will you be able to run these tests without having main() create windows, load files, play sounds, etc each time?

Thankfully, C/C++ has a preprocessor and Visual C++ has the “exclude from build” feature which allows you to exclude certain files whenever the project is built using a specific configuration. Using any of these two features, the first question is easily answered.

The second problem is more tricky — but thankfully, it has already been solved for you: When cfix studio runs unit tests, it is well aware of that running main() might have, let’s say interesting effects — so what it does is simple: It just makes sure that main() is never run! Not only does this ensure that the tests run silently, i.e. without windows popping up etc, it also has the benefit that all unit tests “see” the application in a pristine state: Rather than having to worry about which state main() has brought the application into, you can initialize and clean up any state you need in your Setup and Teardown functions1.

To make a long story short: You can write unit tests in EXE projects in exactly the same manner as you would in a DLL project. No special considerations needed, no project settings that need to be changed, no additional boilerplate code to write. And when you run the EXE outside cfix studio, i.e. hit F5 in Visual Studio or launch the EXE directly, you will not even notice that the EXE houses some unit tests — everything works as normal.

Sounds good? Then wait a few more days and see it in action!

Remarks
1: Needless to say, all global variables are initialized, constructors are run, etc. All CRT initialization happens as normal; only main()/WinMain() is not run. And yes, it also works for apps that link statically to MFC and therefore do not have a “regular” WinMain().


Categories




About me

Johannes Passing, M.Sc., living in Berlin, Germany.

Besides his consulting work, Johannes mainly focusses on Win32, COM, and NT kernel mode development, along with Java and .Net. He also is the author of cfix, a C/C++ unit testing framework for Win32 and NT kernel mode, Visual Assert, a Visual Studio Unit Testing-AddIn, and NTrace, a dynamic function boundary tracing toolkit for Windows NT/x86 kernel/user mode code.

Contact Johannes: jpassing (at) acm org

Johannes' GPG fingerprint is BBB1 1769 B82D CD07 D90A 57E8 9FE1 D441 F7A0 1BB1.

LinkedIn Profile
Xing Profile
Github Profile
Advertisements