My Blahg

April 26, 2007

Combining NAnt with Visual Studio Post Build Events

Filed under: c#, dotnet — treyhutcheson @ 8:32 am

I recently pulled what can only be described as a hack. A dirty hack. The kind of hack that just makes one feel filthy. But in the end, it’s pretty slick.

I’ve been trying to introduce the concept of continuous integration to some of our dotnet projects, with varying results. Most of the developers are open to the idea, but it’s difficult to retrofit processes for current projects. As such, we’re still married to Visual Studio for compilation. Some of our projects do have automated build scripts, but we’ll still use Visual Studio to perform compiles during debugging.

One of our projects is an automated test harness that tests soap requests generated by an assembly against a web service. One of the methods exposed by the web service can be called with an infinite combination of arguments, so the test harness just makes sure that the soap generated by the proxy for known test cases matches baseline soap requests. This test harness allows us to make sure we catch any changes that might effect how the requests are being constructed at runtime.

In order to capture the soap being generated by the dotnet proxy, we have a custom attribute that derives from SoapAttribute. This attribute exposes a static event, so that subscribers can be notified any time a soap request is serialized or deserialized. This attribute must decorate two methods on the web service proxy, which is autogenerated by dotnet’s wsdl tool. That means that if a developer updates the web reference, the code is regenerated, and we lose the method/attribute decoration. Which subsequently causes the test harness to never be notified, effectively breaking the test harness.

So I built a simple NAnt script with an embedded bit of c# script. This script reflects a type, and enforces decoration of named methods with a designated custom attribute. It’s all parameterized, so only the nant task invocations of the script contain the hardcoded type and method names. If the requested method is not decorated by the attribute, it throws an exception, which causes the nant script to fail.

I wired up the script using Visual Studio post-build events. That means that every time Visual Studio rebuilds that assembly, it invokes nant from the command line to execute this script. If the script fails, nant returns a non-zero exit code, which Visual Studio then treats as a compilation failure.

The end result is that if the web reference is refreshed, the assembly cannot be compiled by Visual Studio until the expected web service proxy methods are decorated by our custom attribute.

I could have simply written an nunit test case which would fail appropriately. However, the test case wouldn’t be executed until after the offending code had been checked in, and the automated build scripts were kicked off. This way, we can catch the problem before it’s ever checked in. By the way - this project is not a TDD project.

So, it’s a dirty hack for a few reasons. One is the fact that my nant script contains embedded c# code, of which I am not a fan. Another reason is that every developer’s machine now requires NAnt to be in the environment path.

April 3, 2007

NUnitForms and Modal Dialogs

Filed under: c#, dotnet — treyhutcheson @ 12:35 pm

Two weeks ago I transitioned to another project at work. This project is an automated test harness for an api. The api that is being tested is written in c#. It wraps access to a web service, and provides dialogs for selecting inputs to the web service. This api is an integration layer that is exposed as a set of reverse com interop objects, and is consumed from a legacy Delphi application.

The test harness is used to automate integration tests. It will use the api to make calls against the web service. But to make sure that the requests being sent to the web service are actually coming from the user interface rather than being programmatically generated via the api on an object level, the test harness must drive the user interface itself programmatically.

I came to the project rather late, so the toolset had pretty much been chosen for me. To drive the UI, we’re using the alpha 5 release of NUnitForms 2. This is my first encounter with NUnitForms, and I dig it. I gave up on writing GUI’s years ago, except where absolutely necessary, so I never had any interest in NUnitForms. Now that I’ve used it, I must say that it offers a great amount of utility.

Being an alpha release, I’ve run into a few problems. For the most part, I’ve been able to get around them by changing my approach. However, I encountered an issue that really threw me for a loop.

All of the dialogs exposed through the api are modal. A few of the dialogs are only launched from other modal dialogs. So to get to dialog B, one must first launch Dialog A and click on a button on Dialog A. NUnitForms provides a mechanism for calling back into test cases after a modal dialog has been displayed: the ModalDialogTester class. This class has a public method named ExpectModal, which takes the name of the form to watch for, and a delegate that is used as a callback after the dialog has been displayed.

This mechanism has worked for the most part, except for those cases where a modal dialog launches another modal dialog. I would encounter an AmbiguousNameException, stating that more than one form was present with the same name. What makes the situation so weird is that if I put a breakpoint anywhere between the display of the first modal dialog and the second, I would not receive the exception. When I ran the application outside of the debugging environment, there would be no exception. So I just decided to live with it while debugging.

I was wrong. For a single test script, there was no AmbiguousNameException outside of the debugging environment. But if I processed more than one test script in batch, I would get the exception. I beat my head against this issue for a solid two days. I couldn’t find the source code for any revision of NUnitForms 2, so I just downloaded the source code for version 1.3.1. Looking into the code, the ModalFormTester class internally makes use of the FormFinder class.

Now the FormFinder class is interesting. The FindAll method accepts a string(the name of the form to find), and uses the Win32 API to enumerate all top-level windows(those windows underneath the result of the GetDesktopWindow api). Inside the windows enumeration callback, the FormFinder calls Control.FromHandle(hwnd) to get a reference to the enumerated handle as a WinForms control. This method is static, and I didn’t know it even existed. If it’s not a WinForms control, the result is null. So the result is cast as a Form, and if it isn’t null, the form’s name property is compared against the name argument passed in to the FindAll method. If the name matches, the form instance is added to a collection. The collection is returned from FindAll.

The Find method(singular) internally calls the FindAll method. If no forms are found, it throws a NoSuchControlException. If more than one form is found, it throws an AmbiguousNameException. So I was able to track down where the exception is being thrown, but I couldn’t figure out the condition causing more than one form with the same name to be found. I know there’s only one being instantiated and displayed.

After a few days of futility, I decided that enough was enough. Maybe this wouldn’t be an issue if we weren’t using an alpha build, but that’s out of my control. To solve my problem, I implemented two new classes: CustomFormFinder and ModalFormListener. CustomFormFinder effectively duplicates the logic of the original FormFinder class, except it doesn’t throw any exceptions. It is up to the caller to determine if zero, or more than 1 forms, is an exceptional circumstance. One improvement that I made is that the methods are all static, possible due to dotnet 2’s ability to define delegates anonymously. This way I can have my Windows Enumeration method implemented inline inside of the parent method; the benefit here is that the class is now completely stateless. Another improvement is that I added genericized overloads to both FindForms and FindSingleForm. The generic overloads don’t compare against form name; rather they find all forms of a given type. For example, the method signature of the genericized FindSingleForm looks like this:

public static T FindSingleForm<T>() where T : Form;

After I created and tested the CustomFormFinder class, I implemented the ModalFormListener class. This class has a series of overloaded static methods named RegisterModalCallback. These methods will invoke a callback after a modal form has been displayed. The overloads either work off of form name, or form type T. Like the CustomFormFinder, the methods are static, so all state has been eliminated.

Now the primary difference between my ModalFormListener and NUnitForms’s ModalFormTester is the way I look for forms. I couldn’t find the source code for the ModalFormTester::ExpectModal method, so I’m shooting in the dark here. I assume that it’s using system hooks to be capture any ACTIVATE messages. When a matching form is found, the callback is fired. In the case of my ModalFormListener, I simply fire off a timer into a callback method. Each timer internal I call CustomFormFinder to find the requested form, and if it’s found, I disable the timer and invoke the callback.

It works, and the best part is that I don’t get any unpredictable behavior. And one benefit of using the timer is that the timer event handler is invoked on the main thread, which means that the callback is itself invoked on the main thread.

Blog at WordPress.com.