4

我正在使用 RhinoMocks,并且我有一个 Mock,它有一个我需要作为真实属性的属性 - 在设置时更新其值,并在属性更改时触发 PropertyChanged。

模拟对象的接口本质上是这样的:

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

在创建模拟时,我设置了 PropertyBehavior - 这使得它实际上更新了它的伪造值:

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

但是当我更新值 PropertyChanged 时不会触发。现在,该接口没有实现 INotifyPropertyChanged 接口,因为它是一个接口。如何触发 PropertyChanged?

4

2 回答 2

7

listener 和 mutator 的角色有时可以组合在同一个类中(例如在适配器中),但不应将这两个角色一起测试。

在一项测试中,您只需验证您的听力课程是否PropertyChanged按设计对事件做出反应。您不关心是什么导致该测试中的属性发生变化:

[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; } );
}

在另一个测试中,您验证您的类是否按设计发挥了它的 mutator 角色:

[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);
}

这样,就不需要像您尝试做的那样将真正的逻辑放入您的模拟对象中。这确实需要您为可测试性设计类;很难将这样的测试添加到现有的类中。因此,测试驱动开发的实践。

于 2010-03-01T23:58:04.047 回答
1

我不是 RhinoMocks 方面的专家,但我不会尝试使用我知道的任何模拟框架(我最了解的 TypeMock)来做到这一点。

我会实现类似的东西:

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

对不起。没有什么真正聪明的。但我喜欢这种存根,因为它们可以重复使用。

于 2010-03-01T21:19:37.903 回答