我正在为控制器做一些单元测试,而我正在嘲笑业务组件。 BC有一个公共事件,我在控制器构建时让控制器监听。
我遇到的问题是我不断收到Expectation错误说明: “IBC.add_MessageRaised(MessageEventHandler)预期#:1实际#:0”。
但是,在我的测试中,我没有任何期望。我想知道它是否与设置Controller以监听模拟对象(在这种情况下为BC)上的事件有关。有没有其他方法可以让Controller听取来自模拟的事件?
我也试图想办法让mock来提升MessageRaised事件,但这可能是另一个问题。
以下是代码:
业务组件接口
public interface IBC
{
event MessageEventHandler MessageRaised;
XmlDocument GetContentXml(string path);
}
控制器
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);
}
单元测试
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();
}
}
答案 0 :(得分:3)
以下代码似乎使用了一个模拟对象,并且通过使用它会导致期望被记录:
Controller _controller = new Controller(_bc);
您正在使用这样的模拟对象:
_bc.MessageRaised += MessageWatch;
因此,您已设置了将事件处理程序添加到_bc.MessageRaised的期望。这在回放块中不会发生,因此会引发错误。
另请参阅this question有关对象何时进入记录状态的信息。老实说,如果对象无论如何都隐式进入记录状态,我也不明白为什么会有明确的记录语法。
答案 1 :(得分:0)
我通过结合一些东西(不完全确定它是如何工作的,但确实如此)来实现它:
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);
这使得问题中的测试成功,并且让我在其他测试中从Mock对象中引发事件,例如:
[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));
}
}
希望别人觉得这很有用!
答案 2 :(得分:0)
以下是我如何处理从模拟对象中引发事件的方法:
port.DataPacketReceived += null;
packetReceivedRaiser =
LastCall.IgnoreArguments().Repeat.Any().GetEventRaiser();
在这种情况下,port是一个带有名为DataPacketReceived的事件的模拟对象。
理想情况下,我总是尝试将模拟对象置于播放模式,然后再将它们传递给被测系统。这避免了任何“意外期望”。