views:

145

answers:

2

I am using RhinoMocks, and I have a Mock which has a property I need to behave as a real property - updating its value when set, and also trigger PropertyChanged when the property is changed.

The interface of the mocked object is in essence this:

public interface IFoo
{
    event PropertyChangedEventHandler PropertyChanged;
    int Bar { get; set; }
}

When creating the mock I set PropertyBehavior - which makes it actually update its faked value:

var mocks = new MockRepository();
var fakeFoo = mocks.DynamicMock<IFoo>();
SetupResult.For(fakeFoo.Bar).PropertyBehavior();

But when I update the value PropertyChanged isn't triggered. Now, the interface doesn't implement the INotifyPropertyChanged interface as it is an interface.. How can I make PropertyChanged triggered?

+1  A: 

I'm not an expert in RhinoMocks, but I wouldn't try to do that with any of the mock-framework I know (TypeMock I know the most).

I would implement something like:

public class FooFake: IFoo
{
    public event PropertyChangedEventHandler PropertyChanged;
    int _bar;
    public int Bar
    {
       set
       {
           if( PropertyChanged != null )
               PropertyChanged();
           _bar = value;
       }
       get
       {
          return _bar;
       }
    }
}

Sorry. Nothing really clever. But I like this kind of stub as they can be resused.

Enceradeira
+1 but this is not a stub. The unit testing term for a manually created, simplified implementation is a "fake". This post from the google testing blog gives some good definitions: http://googletesting.blogspot.com/2008/06/tott-friends-you-can-depend-on.html And this article by Martin Fowler: http://martinfowler.com/articles/mocksArentStubs.html
Wim Coenen
You are right. I have to change my habit to call that stub!I changed the example now from FooStub to FooFake.
Enceradeira
+4  A: 

The role of listener and mutator may sometimes be combined in the same class (e.g. in an adapter), but both roles should not be tested together.

In one test, you merely verify that your listening class reacts to the PropertyChanged event as designed. You don't care about what caused the property to change in that test:

[Test]
public void Updates_Caption_when_Bar_PropertyChanged()
{
   var foo = MockRepository.GenerateStub<IFoo>();
   foo.Bar = "sometestvalue1";
   var underTest = new UnderTest(foo);

   // change property and raise PropertyChanged event on mock object
   foo.Bar = "sometestvalue2";
   foo.Raise(x=>x.PropertyChanged+=null,
       foo,
       new PropertyChangedEventArgs("Bar"));

   // assert that the class under test reacted as designed
   Assert.AreEqual("sometestvalue2", underTest.Caption);

   // or if the the expected state change is hard to verify, 
   // you might just verify that the property was at least read
   foo.AssertWasCalled(x => { var y = foo.Bar; } );
}

In another test, you verify that your class plays its mutator role as designed:

[Test]
public void Reset_clears_Foo_Bar()
{
   var foo = MockRepository.GenerateStub<IFoo>();
   foo.Bar = "some string which is not null";
   var underTest = new UnderTest(foo);

   underTest.Reset();

   // assert that the class under test updated the Bar property as designed
   Assert.IsNull(foo.Bar);
}

This way, it is never necessary to put real logic into your mock objects like you are trying to do. This does require that you design your classes for testability; it is hard to add such tests to existing classes. Hence the practice of test driven development.

Wim Coenen