C# and Moq, raise event declared in interface from abstract class mock
I am writing the unit test and receive exception when trying to raise the event from abstract class mock. Here is the sample code:
public abstract class AbstractBase : EntityObject
{}
[TestMethod]
public void MyTest()
{
var mock = new Mock<AbstractBase>();
var notificationMock = entityMock.As<INotifyPropertyChanged>();
var propertyChangedMapper = new PropertyChangedMapper();
bool eventReceived = false;
propertyChangedMapper.MyPropertyChanged +=
(sender, eventArgs) =>
{
eventReceived = true;
};
propertyChangedMapper.Subscribe((AbstractBase)notificationMock.Object);
Assert.IsFalse(eventReceived);
notificationMock.Raise(e=>e.PropertyChanged += null,
new PropertyChangedEventArgs("Property1"));
Assert.IsTrue(eventReceived);
}
Obviously I could use mock on INotifyPropertyChanged
and event is risen just fine, but inside of PropertyChangedMapper
I need to cast the sender to AbstractBase
which fails if using Mock<INotifyPropertyChanged>
EDIT:
As per suggestion using Mock.As<>()
seems to be the right way to go, the only problem above is that the event risen from notificationMock
has nothing to do with the original mock of the object. Code:
notificationMock.Object.PropertyChanged += (s, e) =>
{开发者_如何学Go
var result = "this one is fired as it should";
};
mock.Object.PropertyChanged += (s, e) =>
{
var result = "this one is not called but is actually what I need";
};
notificationMock.Raise(e => e.PropertyChanged += null,
new PropertyChangedEventArgs("Property1"));
You may be able to do the desired cast if you make your mock a mult-mock. Since Moq mocks are tied to an individual type via the generic argument, you must explicitly progressively add additional interfaces or super-classes to the mock, and then use the end product in your test. A quick example of how to do this is below.
var baseMock = new Mock<AbstractBase>();
var inpcMock = baseMock.As<INotifyPropertyChanged>();
// ...setup event...
propertyChangedMapper.Subscribe(inpcMock.Object);
// ... assertions ...
Given the way you're doing this, there is no implementation of the event. The interface itself is just the contract that says "I have a PropertyChanged event." If you want to raise that event, you have to provide a handler, even if it doesn't do anything. Implement the PropertyChanged event in your mocked class to raise the event.
UPDATE:
Try this code for your AbstractBase:
public abstract class AbstractBase : INotifyPropertyChanged
{
public virtual event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
Is your PropertyChanged
event declared as a virtual
event?
public abstract class AbstractBase : INotifyPropertyChanged
{
public virtual event PropertyChangedEventHandler PropertyChanged;
}
(See also: Jon Skeet on virtual events.)
精彩评论