I am running some unit tests on a WCF service. The service is configured to include exception details in the fault response (with the following in my service configuration file).
<serviceDebug includeExceptionDetailInFaults="true" />
If a test causes an unhandled exception on the server the fault is received by the client with a fully populated server stack trace. I can see this by calling the exception's ToString()
method. The problem is that this doesn't seem to be output by any of the test runners that I have tried (xUnit, Gallio, MSTest). They appear to just output the Message and the StackTrace properties of the exception.
To illustrate what I mean, the following unit test will output three sections:
public void Test()
{
try
{
service.CallMethodWhichCausesException();
}
catch (Exception ex)
{
Console.WriteLine(ex); // this outputs the information I would like
throw;
}
}
Edit: However, I would prefer that I was not forced to catch the exception in each test and write it to the console in order to ascertain the content within a FaultException
object's Detail
property.
For example,
public void Test()
{
service.CallMethodWhichCausesException();
}
Having this information will make the initial phase of testing and deployment a lot less painful.
I know I can just wrap each unit test in a generic exception handler and write the exception to the console and rethrow (as above) within all my unit tests but that seems a very long-winded way of achieving this (and would look pretty awful).
Does anyone know if there's any way to get this information included whenever an unhandled exception occurs? Is there a setting that I am missing? Is my service configuration lacking in proper fault handling? Perhaps I could write some kind of plug-in / adapter for some unit testing framework? Perhaps theres a different unit testing framework which I should be using instead!
My actual set-up is xUnit unit tests executed via Gallio for the development environment, but I do have a separate suite of "smoke tests" written which I would like to be able to have our engineers run via the xUnit GUI test runner (or Gallio or whatever) to simplify the final deployment.
Thanks.
Adam
I think I have found a solution. Oleg Sych has implemented a WCF behaviour which transparently marshals exceptions from the server to client, raising them on the client as if they had occurred there.
It's as simple as adding a service behaviour attribute to the service contract (interface).
This approach is especially beneficial if it is decided that existing code, written to execute within a single process, should distributed via WCF services. It means that it can be achieved without requiring any changes to the client's exception handling (e.g. you can still handle a SecurityException
on the client instead of having to handle a FaultException<SecurityException>
when you move to a more distributed design).
The post can be found here: http://www.olegsych.com/2008/07/simplifying-wcf-using-exceptions-as-faults/
Since my WCF services are using a mixture of ws2007HttpBinding the basicHttpBinding (for interoperability), I had to make a few changes to the code (as mentioned in the comments of the post above). Specifically:
In ExceptionMarshallingMessageInspector.AfterReceiveReply
:
Exception exception = faultDetail as Exception;
if (exception != null)
{
// NB: Error checking etc. excluded
// Get the _remoteStackTraceString of the Exception class
FieldInfo remoteStackTraceString = typeof(Exception).GetField(
"_remoteStackTraceString",
BindingFlags.Instance | BindingFlags.NonPublic);
// Set the InnerException._remoteStackTraceString to the current InnerException.StackTrace
remoteStackTraceString.SetValue(
exception,
exception.StackTrace + Environment.NewLine);
throw exception;
}
...and in ExceptionMarshallingMessageInspector.ReadFaultDetail
I made a change so that it looks for a detail node with a local name equal to either "Detail" (for ws2007HttpBinding" or "detail" (for basicHttpBinding).
I hope this helps.
Adam