UPDATE: As I suspected, this functionality was right in front of my face – it’s called PredicateConstraint in Rhino Mocks. I also realize that I managed to completely ignore the existence of Predicate<T> in the framework, and write my own predicate delegate. Hey, I was on a roll.
Rhino Mocks has a PropertyConstraint class that allows you to check the values on properties of objects passed into the method as part of the verification for that method being called. Unfortunately, the name of the property is specified as a string, which means the benefits of strong-typing that Rhino Mocks is normally so good at preserving are lost. Here’s an example (using Rhino Mocks 3.3 and .NET 2.0):
[Test] public void Main_Form_Should_Show_Start_Panel_On_Load() { MockRepository mockRepository = new MockRepository(); IMainFormView mockView = mockRepository.DynamicMock<IMainFormView>(); IEventRaiser loadEventRaiser = GetEventRaiserFor(delegate { mockView.Load += null; }); Expect.Call( delegate { mockView.SetMainFormControlVisibility(null); }).Constraints(new PropertyConstraint("StartPanelIsVisible", Is.Equal(true))); mockRepository.ReplayAll(); IMainFormController controllerUnderTest = new MainFormController(mockView); loadEventRaiser.Raise(mockView, EventArgs.Empty); mockRepository.VerifyAll(); }
Basically, the view’s method SetMainFormControlVisibility takes an object with a property called StartPanelIsVisible. We want to make sure that when the controller calls this method, this property is set to true on the parameter object. In fact, that is the sole reason for the existence of this test. Using a string to specify the property name isn’t very conducive to refactoring, and it would be nice to have intellisense and compile-time argument checking available when we specify the constraints for an object’s state. I found myself writing this class:
public class PropertyConstraint<T> : AbstractConstraint where T : class { public delegate bool ConfirmPropertyState<U>(U statefulObject); private readonly ConfirmPropertyState<T> confirmPropertiesMatch; public PropertyConstraint(ConfirmPropertyState<T> confirmPropertiesMatch) { this.confirmPropertiesMatch = confirmPropertiesMatch; } public override bool Eval(object obj) { AssertObjectIsCorrectType(obj); T objectToConfirmStateOf = Cast(obj); return confirmPropertiesMatch(objectToConfirmStateOf); } public override string Message { get { return String.Format( "The properties of the passed in {0} do not match the expectations of the constraint.", typeof(T).FullName); } } private static void AssertObjectIsCorrectType(object obj) { if (!(obj is T)) { throw new ArgumentException( String.Format( "PropertyConstraint expected to evaluate an object of type {0} but was pass an object of type {1}", typeof (T).FullName, obj.GetType().FullName)); } } private static T Cast(object obj) { return obj as T; } }
Which changes our test to look like this:
[Test] public void Main_Form_Should_Show_Start_Panel_On_Load() { MockRepository mockRepository = new MockRepository(); IMainFormView mockView = mockRepository.DynamicMock<IMainFormView>(); IEventRaiser loadEventRaiser = GetEventRaiserFor(delegate { mockView.Load += null; }); PropertyConstraint<MainFormControlVisibility> startPanelIsVisible = new PropertyConstraint<MainFormControlVisibility>( delegate(MainFormControlVisibility match) { return match.StartPanelIsVisible; }); Expect.Call( delegate { mockView.SetMainFormControlVisibility(null); }).Constraints(startPanelIsVisible); mockRepository.ReplayAll(); IMainFormController controllerUnderTest = new MainFormController(mockView); loadEventRaiser.Raise(mockView, EventArgs.Empty); mockRepository.VerifyAll(); }
I admit this is pretty clunky (it looks better with lambdas), but it achieves the object of getting rid of the string for property specification.
I’m almost sure something like this exists in Rhino Mocks as it is, but I couldn’t find it, so I thought I’d share this. Again, I’m using an older version of Rhino Mocks (3.3).
Comments