Archive for February, 2010
Unit testing the IAsyncResult pattern
The IAsnycResult pattern is a way of executing asynchronous operations using a BeginOperation and an EndOperation method. You can either use a callback or a wait handle to complete an operation.
Although it is a little less intuitive than the event based pattern that WCF offers by default, it has the advantage that you can run it directly against a service contract of a WCF service. Unit testing the pattern is also on the slightly non-unintuitive side, but not as bad as it looks on first glance.
Let’s unit-test this: we’ve got an asynchronous call of a method on a WCF service that echos a value.
public class EchoViewModel
{
// In this example, the service client is passed into the ViewModel via DI
[Dependency]
public IEchoService EchoService
{
get;
set;
}
private string _toBeEchoed;
public string ToBeEchoed
{
get
{
return _toBeEchoed;
}
set
{
_toBeEchoed = value;
Echo( _toBeEchoed );
}
}
public string Echoed
{
get; set;
}
protected void Echo(string value)
{
EchoService.BeginEcho( value, EchoComplete, null );
}
protected void EchoComplete(IAsyncResult asyncResult)
{
Echoed = EchoService.EndEcho( asyncResult );
}
}
Now what do we need to cover in a good unit test?
- The Begin method of the web service is called. This method starts an asynchronous operation. It accepts the parameters that are passed to the web service (and that are defined on the synchronous operation), as well as two extra parameters: The callback method to call when the web service call completes, and an object to transfer arbitrary state to that callback method.
The test should cover that the method is called with the correct parameters. - When the service call completes, the callback method is called. This method has a single parameter: the state of the asynchronous method call; an object that supports the interface IAsyncResult. The test needs to verify that this method is called.
- The callback method calls into the End method of the web service. This method always has a single parameter: the IAsyncResult that is passed to the callback method. The End method returns the result of the web service call, or throws an exception if the web service call has not succeeded.
To observe these method calls, the service arrangement needs to set up expectations about what it going to happen – enter Rhino.Mocks.
Let’s see what we can do to arrange a test setup:
public void ArrangeEchoService(string toBeEchoed, string result)
{
// Prepare the result of the asyncronous operation. Since you can't easily
// instantiate IAsyncResult, use a stub object - you find it in the downloadable
// code (see end of article).
IAsyncResult asyncResult = new StubAsyncResult( null );
// Call Rhino.Mocks to expect BeginEcho is called with the right parameters.
// Because the callback method is protected, we cannot directly set up a
// parameter constraint against it; instead, we accept anything as a callback.
// The correctness of the callback is asserted by actually calling it.
var expectBeginMethod = _tested.EchoService
.Expect( x => x.BeginEcho( null, null, null ) )
.IgnoreParameters()
.Repeat.Once()
.Constraints(
Parameter.Is.Equal( toBeEchoed ),
Parameter.Is.Anything(),
Parameter.Is.Null()
);
// When the Begin method is called, call the provided callback method.
// Using the AsyncMethodCall delegate allows providing the code for the Do
// method as a lambda expression.
expectBeginMethod
.Do( new AsyncMethodCall( (param1, callback, state) =>
{
callback.Invoke( asyncResult );
return asyncResult;
} ) );
// Expect the End method of the asynchronous operation to be called.
// Return the prepared service result.
_tested.EchoService
.Expect( x => x.EndEcho( asyncResult ) )
.Return( result )
.Repeat.Once();
}
A test method that uses this arrangement is fairly simple
[Test]
public void Value_StandardBehavior_CallsServiceAndSetsEchoedValue()
{
// Arrange
using (_mock.Record())
{
ArrangeEchoService( "ToBeEchoed", "Echoed" );
}
// Act
using (_mock.Playback())
{
_tested.ToBeEchoed = "ToBeEchoed";
}
// Assert
Assert.That( _tested.Echoed, Is.EqualTo( "Echoed" ) );
}
Conclusion:
So we’ve got a fairly decent way of testing asynchronous operations using the IAsyncResult pattern, and callbacks. While setting up the operation behavior is quite a bit of effort, writing the tests itself is fairly easy. To streamline the process in a larger process, the Arrangement methods could be code-generated from the method signature (using T4 or alike).
More evaluation and meetings
I got some quite passionate feedback on my latest frowning on capturing feedback for internal trainings. In short, the reaction was that there are some obvious advantages to gain in capturing feedback, nothing to lose, and I didn’t really show a lot of innovative spirit. My main claim was that creating and evaluating the feedback materials could easily become a waste of time because participants would not be motivated to return feedback.
The key is to make giving feedback compelling, fun, and fast. Only ask one or two simple questions like:
What was the most useful thing you learned in this session?
If you could change one thing for the next group of participants for this session, what would it be?
What were you expecting that you did not get from the session?
And then, you can do better than filling out paper. Using an online tool lets your participants give their feedback when they are ready for it – and that is probably not directly after the session when everyone is rushing out for lunch or a few beers, but later in the hotel room or via their smartphone. And of course, an online tool does not pile up on your desk in an untidy fashion (yes, I’m the kind of person whose desk is always a mess).
I stumbled across a new thing called BetterMe - its primary focus is on personal feedback, but it works perfectly for a serious of sessions. BetterMe lets you send out questions, and a (predefined) set of ratings to a group of people, who then receive an invitation to come in and provide anonymous feedback. Well yeah, there are drawbacks – the rating questions can only be chosen from a small predefined set, you need to log on to provide feedback, support for small device isn’t great. But BetterMe really shines as a personal tool for accepting and giving feedback, in a professional or personal frame. (OK, the templates for personal questions are a little weird: How am I in bed – rate 1-10). You can try this out on me: go to BetterMe, create a login, and send some feedback to chr.heger@gmail.com.
And then there’s Ketchup. Ketchup is a minimalistic planning tool for meetings, and very much focused on exactly that. You start by creating a meeting in Ketchup, invite some people (Ketchup sends out the invitations), and share the URL of public meetings. Then when the meeting is on the way or over you can add some notes. The whole meeting can be printed nicely, and there are decent export features into calendars. Ketchup does nothing that you could not do with your Outlook or Google Calendar, but it provides a very streamlined and concentrated user interface.
Finally, a visit on MeetOrDie can saves you the effort of actually running a meeting at all, as it precisely predicts the outcome of a meeting.
Piece of Proxy Cake
I’m not 100% decided if I like C#4′s dynamic objects*, but one thing is for sure: creating proxies for types has never been easier.
Proxies are a great way of injecting behavior into existing objects There are powerful and proven utilities for creating proxies in .NET that use Reflection Emit – e.g. the Proven and Honorable Castle DynamicProxy.
C# 4.0 dynamic language features add a new, super-simple way to roll your own proxy implementation: all you need to do is derive from System.Dynamic.DynamicObject, and overload some methods. So here we go:
using System;
using System.Dynamic;
using System.Reflection;
namespace GreenIcicle.DynamicProxy
{
/// <summary>
/// Simple implementation of a proxy.
/// </summary>
/// <remarks>
/// This is not production-quality code, and some things (indexer etc)
/// are just missing.
/// Be nice to the planet: please don't paste into anything you want run
/// your nuclear power plant with.
/// </remarks>
/// <typeparam name="T">Type of the object wrapped by the proxy.</typeparam>
public class Proxy<T> : DynamicObject
where T : class
{
/// <summary>
/// Creates a proxy around an instance of <typeparamref name="T"/>.
/// </summary>
/// <param name="wrapped">The object wrapped by the proxy.</param>
public Proxy( T wrapped )
{
if (wrapped == null)
{
throw new ArgumentNullException( "wrapped" );
}
Wrapped = wrapped;
}
/// <summary>
/// The object wrapped by the proxy.
/// </summary>
protected T Wrapped
{
get;
private set;
}
/// <summary>
/// Gets the value of a property on the wrapped object.
/// </summary>
public override bool TryGetMember( GetMemberBinder binder, out object result )
{
bool propertyExists = false;
result = null;
Type type = typeof( T );
PropertyInfo prop = type.GetProperty( binder.Name );
if (prop != null)
{
result = prop.GetValue( Wrapped, null );
propertyExists = true;
}
return propertyExists;
}
/// <summary>
/// Sets the value of a property on the wrapped object.
/// </summary>
public override bool TrySetMember( SetMemberBinder binder, object value )
{
bool propertyExists = false;
Type type = typeof( T );
PropertyInfo prop = type.GetProperty( binder.Name );
if (prop != null)
{
prop.SetValue( Wrapped, value, null );
propertyExists = true;
}
return propertyExists;
}
/// <summary>
/// Executes a method on the wrapped object.
/// </summary>
public override bool TryInvokeMember( InvokeMemberBinder binder, object[] args, out object result )
{
bool methodExists = false;
result = null;
Type type = typeof( T );
MethodInfo method = type.GetMethod( binder.Name );
if (method != null)
{
result = method.Invoke( Wrapped, args );
methodExists = true;
}
return methodExists;
}
/// <summary>
/// Converts the instance of the proxy to the type that it wraps.
/// </summary>
public override bool TryConvert( ConvertBinder binder, out object result )
{
Type type = typeof( T );
bool canConvert = false;
result = null;
if (binder.Type.IsAssignableFrom( type ))
{
result = Wrapped;
canConvert = true;
}
return canConvert;
}
}
}
The principle is that DynamicObject provides virtual methods to provide the implementation of properties and methods. The MemberBinder object carry the name of the requested property or method. This proxy uses reflection to see if the type member exists, and invokes it.
The thing I like the most is that converting the proxy back into the wrapped type:
RobotDomainObject robotOne = new RobotDomainObject(); dynamic proxy = new Proxy<RobotDomainObject>( robotOne ); RobotDomainObject robotTwo = proxy;
This proxy implementation by itself is not yet every useful. The fun begins where the proxy is extended to provide extra behavior. Here, I want to extend the proxy to support dynamic properties in addition to the ones of the wrapped object.
using System;
using System.Collections.Generic;
using System.Dynamic;
namespace GreenIcicle.DynamicProxy
{
/// <summary>
/// Simple implementation of a proxy that supports dynamically added properties
/// in addition to those of the wrapped object.
/// </summary>
/// <remarks>
/// This is not production-quality code, and some things (indexer etc)
/// are just missing.
/// Be nice to the planet: please don't paste into anything you want run
/// your nuclear power plant with.
/// </remarks>
/// <typeparam name="T">Type of the object wrapped by the proxy.</typeparam>
public class Expander<T> : Proxy<T>
where T : class
{
private IDictionary<string, object> m_DynamicProprtyValues;
/// <summary>
/// Creates a proxy around an instance of <typeparamref name="T"/>.
/// </summary>
/// <param name="wrapped">The object wrapped by the proxy.</param>
public Expander(T wrapped)
: base( wrapped )
{
// Empty constructor
}
/// <summary>
/// Dictionary of dynamically added property values.
/// </summary>
protected IDictionary<string, object> DynamicProprtyValues
{
get
{
if (m_DynamicProprtyValues == null)
{
m_DynamicProprtyValues = new Dictionary<string, object>( StringComparer.Ordinal );
}
return m_DynamicProprtyValues;
}
}
/// <summary>
/// Gets the value of a property on the wrapped object, or, if it does not exist,
/// retrieves a dynamically added property.
/// </summary>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
bool propertyExists = base.TryGetMember( binder, out result );
if (!propertyExists)
{
if (DynamicProprtyValues.ContainsKey( binder.Name ))
{
result = DynamicProprtyValues[ binder.Name ];
}
}
return true;
}
/// <summary>
/// Sets the value of a property on the wrapped object, or, if it does not exist,
/// creates a dynamically added property.
/// </summary>
public override bool TrySetMember(SetMemberBinder binder, object value)
{
bool propertyExists = base.TrySetMember( binder, value );
if (!propertyExists)
{
DynamicProprtyValues[ binder.Name ] = value;
}
return true;
}
}
}
So now we’ve got a proxy that accepts just any property. What it is good for: MVVM! In a WPF or SIlverlight application, using this kind of extensible proxy can remove the need to create additional objects – and data binding expressions don’t adhere to strong typing anyway.
* Jason Olson said on Hanselminutes that he’d consider dynamic classes in C# mostly as an interoperability feature to fully dynamic languages, and I’d mostly agree to that. If you want to program in a dynamic language, just do so. C# isn’t one. There are some rare legit use cases; methinks proxy generation is one of these.
Evaluation sheets for internal training?
We’ll be running quite a massive series of internal developer trainings in the next months, and in a planning meeting, I got into a short but heated opinion exchanges about whether we should hand out evaluation sheets after the sessions or not. I was against it. And now I wonder if I’m right.
Sessions will be held by members of the development team, the audience are developers too; there should be two dozens of people. There’s going to be one or two repetitions of the sessions.
Pro evaluation sheets:
- The speaker gets feedback on how he was doing. This helps her/him to improve both the session (slides, script, timing) and presentation skills.
- Participants feel more involved. Maybe they can even vent away some frustration and feel better.
Contra evaluation sheets: (you might notice, I’m biased towards this side of the argument. Hence the longer and more arguments. Which does not make it right per se.)
- I don’t like filling them out, so I presume nobody does. I would not expect an outrageously high return rate. Given that you only get a few data points (there are 12 participants in total), what’s the validity?
- The speakers are just developers; teaching groups is an exception from their day job. Everyone will give their session maybe two times. So even if you get a very clear indication of things you could improve, there’ not that much opportunity.
- Designing a questionnaire, distribution of sheets, and evaluation are all tasks that take their time – a scarce resource that I feel could be of some use elsewhere.
In the end, I still think it’s just not worth the effort.
Free NUnit integration for Visual Studio
It’s been around for half a year now, but I totally missed that there is a free&open tool out there that lets you run NUnit tests from within Visual Studio. The thing is called Visual NUnit (documentation and download available from that link). It does exactly what it promises to do – run NUnit tests from within Visual Studio, and debug without attaching the debugger to NUnit first, and that’s it – and performs very solidly; I’ve tested it with VS2008 with a 2000+ test suite, and with the RC of VS2010 (but not with that many tests).
No hard feelings, but I always thought that the price tag for TestDriven.Net was a little over the top; maybe worth paying, but not worth the fight of getting the budget for.
Thanks Tommi Laukkanen for putting this together! (And BTW, there another Tommi Laukkanen who’s made the mobile Twitter app Twim that I use on the e71. But they’re not the same).
Wednesday Morning Rant
It’s early, it’s raining, the conductor just told me the trains won’t be running tomorrow, but I’m fine because I can cool my temper venting about:
Steam.
Yesterday on the train home I fired up Machinarium (an awesome and stylish puzzle-solving game). The only problem with it is that you can get it on Steam.
Now instead of just starting the game, Steam told me it couldn’t because I thought it urgently needed to phone home and tell the guys at Valve about what I did yesterday (or whatever it does), but that’s OK, I’d love to exchange a little privacy for the opportunity to buy games without having to wait for the DVDs to arrive (especially because the laptop does not have a drive). So I plugged in the 3G stick and learned that what Steam really wanted to do was to update itself. After some train stations of watching the progress bar slowly creep to the 20% mark it occurred to me that it wouldn’t be finished until I got home, and would have churned away half my data plan. Now really. 30+ MB for starting a game that I’ve already got installed?
eBay.
I’ve received a friendly e-mail from them that since I’ve sold less than 50 items of stuff over the years, I’d have to offer PayPal for each of my future auctions. I know I have a PayPal account, but it must have fallen behind the book shelf or book taken out by the dog; in any case, it’s in disuse since years. And the experiences with it weren’t that great that I’d say I miss it. For the odd toy or spare electronics parts that I used to sell I just won’t bother revitalizing may PayPal account or creating a new one. In addition, I find it interesting that eBay actually rises the bar for new potential sellers – I’m not sure if that serves them. Well I am. It won’t.