我正在使用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?
答案 0 :(得分:7)
侦听器和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);
}
这样,就没有必要像你想要的那样将真实逻辑放入你的模拟对象中。这确实需要您设计可测试性的类;很难将这些测试添加到现有的类中。因此test driven development的做法。
答案 1 :(得分: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;
}
}
}
对不起。没有什么比这更聪明了。但我喜欢这种存根,因为它们可以被重用。