当更改时使模拟触发PropertyChanged

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被触发?

2个回答

7

侦听器和修改器的角色有时可以结合在同一个类中(例如适配器),但不应同时测试两个角色。

在一个测试中,你只需验证你的监听类是否按设计方式对 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; } );
}

在另一个测试中,您验证您的类按照设计发挥了其改变器作用:
[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);
}

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


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

抱歉,没有什么特别聪明的内容。但我喜欢这种桩文件,因为它们可以被重复使用。


1
+1 但这不是一个桩件。单元测试术语中,手动创建的简化实现称为“伪造”。这篇来自谷歌测试博客的帖子提供了一些很好的定义:http://googletesting.blogspot.com/2008/06/tott-friends-you-can-depend-on.html 还有这篇由马丁·福勒写的文章:http://martinfowler.com/articles/mocksArentStubs.html - Wim Coenen
你说得对。我必须改变我的习惯,不再称呼那个存根! 现在我已经将示例从FooStub更改为FooFake。 - Enceradeira

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接