Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making mocks trigger PropertyChanged when changed

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?

like image 419
stiank81 Avatar asked Feb 28 '23 11:02

stiank81


1 Answers

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.

like image 144
Wim Coenen Avatar answered Mar 06 '23 20:03

Wim Coenen