Reputation: 5417
I'm doing some unit tests for a controller, and I'm mocking the business component. The BC has a public event that I have the controller listening to when the controller is constructed.
The problem I'm having is I keep getting an Expectation error stating: "IBC.add_MessageRaised(MessageEventHandler) Expected#:1 Actual#:0".
However, I don't have any expectation of that kind in my test. I'm wondering if it has to do with setting the Controller to listen to an event on a mocked object (the BC in this case). Is there another way I can get the Controller to listen to an event coming from a mock?
I'm also trying to think of a way to get the mock to raise the MessageRaised event, but that might be another question altogether.
Here is the code:
Business Component Interface
public interface IBC
{
event MessageEventHandler MessageRaised;
XmlDocument GetContentXml(string path);
}
Controller
private readonly IBC _bc;
public Controller(IBC bc)
{
_bc = bc;
_bc.MessageRaised += MessageWatch;
}
private void MessageWatch(object sender, MessageEventArgs e)
{
if (MessageRaised != null)
MessageRaised(sender, e);
}
Unit Test
MockRepository Mockery = new MockRepository();
TFactory _tFac;
IView _view;
Presenter _presenter = new Presenter();
IBC _bc = Mockery.DynamicMock<IBC>();
Controller _controller = new Controller(_bc);
_tFac = new TFactory(Mockery);
_tFac.Create(ref _view, ref _presenter, ref _controller);
[Test]
public void View_OnGetContentXmlButtonClick_Should_SetXmlInView()
{
//SETUP
XmlDocument xmlDocument = new XmlDocument();
using ( Mockery.Record() )
{
SetupResult.For(_view.FilePath).Return("C:\Test.txt");
Expect.Call(_bc.GetContentXml("C:\Test.txt")).Return(xmlDocument);
_view.Xml = xmlDocument.InnerXml;
}
//EXECUTE
using ( Mockery.Playback() )
{
_presenter.View_OnGetContentXmlButtonClick();
}
}
Upvotes: 2
Views: 536
Reputation: 56640
Here's how I deal with raising events from a mock object:
port.DataPacketReceived += null;
packetReceivedRaiser =
LastCall.IgnoreArguments().Repeat.Any().GetEventRaiser();
In this case, port is a mock object with an event called DataPacketReceived.
Ideally, I always try to put my mock objects in playback mode before passing them to the system under test. This avoids any "unexpected expectations".
Upvotes: 0
Reputation: 5417
I got it to work by combining a few things (not entirely sure how it works, but it does):
IEventRaiser _raiser;
MockRepository Mockery = new MockRepository();
TFactory _tFac;
IView _view;
Presenter _presenter = new Presenter();
IBC _bc = Mockery.DynamicMock<IBC>();
_bc.MessageRaised += null;
_raiser = LastCall.GetEventRaiser();
Controller _controller = new Controller(_bc);
Mockery.BackToRecord(_bc,BackToRecordOptions.None);
_tFac = new TFactory(Mockery);
_tFac.Create(ref _view, ref _presenter, ref _controller);
This made the test in the question work, as well as letting me raise an event from the Mock object in other tests, like:
[Test]
public void View_OnGetContentXmlButtonClick_When_FileDoesNotExist_Should_RelayMessage()
{
//SETUP
XmlDocument xmlDocument = new XmlDocument();
using (Mockery.Record())
{
SetupResult.For(_view.FilePath).Return("C:\Test.txt");
Expect.Call(_bc.GetContentXml("C:\Test.txt")).Return(null);
_view.Xml = xmlDocument.InnerXml;
_view.Message = MESSAGE_FILE_NOT_EXIST;
}
//EXECUTE
using (Mockery.Playback())
{
_presenter.View_OnGetContentXmlButtonClick();
_raiser.Raise(_bc, new MessageEventArgs(MESSAGE_FILE_NOT_EXIST));
}
}
Hope others find this useful!
Upvotes: 0
Reputation: 66733
It seems the following code uses a mock object and, by using it, causes an expectation to be recorded:
Controller _controller = new Controller(_bc);
You are using the mock object like this:
_bc.MessageRaised += MessageWatch;
As a result, you have set up an expectation that an event handler is added to _bc.MessageRaised. This does not happen in the playback block, so an error is raised.
See also this question about when an object enters the record state. To be honest, I also don't understand why there is an explicit record syntax if objects enter the record state implicitly anyway.
Upvotes: 3