.net 使用Dispatcher时的单元测试CompositePresentationEvent
我正在使用Prism/Composite应用程序库,并尝试使用EventAggregator对订阅CompositePresentationEvent的一些代码进行单元测试。引发事件的代码正在另一个线程上引发事件,因此我使用ThreadOption.UIThread订阅事件 当事件引发回调时,它使用应用程序调度程序将其放入UI线程。这在正常执行期间是可以的,但是在单元测试期间没有调度程序。CompositePresentationEvent中的代码如下所示:.net 使用Dispatcher时的单元测试CompositePresentationEvent,.net,unit-testing,prism,dispatcher,.net,Unit Testing,Prism,Dispatcher,我正在使用Prism/Composite应用程序库,并尝试使用EventAggregator对订阅CompositePresentationEvent的一些代码进行单元测试。引发事件的代码正在另一个线程上引发事件,因此我使用ThreadOption.UIThread订阅事件 当事件引发回调时,它使用应用程序调度程序将其放入UI线程。这在正常执行期间是可以的,但是在单元测试期间没有调度程序。CompositePresentationEvent中的代码如下所示: private IDispa
private IDispatcherFacade UIDispatcher
{
get
{
if (uiDispatcher == null)
{
this.uiDispatcher = new DefaultDispatcher();
}
return uiDispatcher;
}
}
public class DefaultDispatcher : IDispatcherFacade
{
/// <summary>
/// Forwards the BeginInvoke to the current application's <see cref="Dispatcher"/>.
/// </summary>
/// <param name="method">Method to be invoked.</param>
/// <param name="arg">Arguments to pass to the invoked method.</param>
public void BeginInvoke(Delegate method, object arg)
{
if (Application.Current != null)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, method, arg);
}
}
}
专用IDispatcherUIDispatcher
{
得到
{
如果(uiDispatcher==null)
{
this.uiDispatcher=新的DefaultDispatcher();
}
返回调度程序;
}
}
公共类DefaultDispatcher:IDispatcherFacade
{
///
///将BeginInvoke转发到当前应用程序的。
///
///要调用的方法。
///传递给被调用方法的参数。
public void BeginInvoke(委托方法,对象参数)
{
if(Application.Current!=null)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,method,arg);
}
}
}
问题在于CompositePresentationEvent与DefaultDispatcher绑定,如果没有应用程序运行,则此dispatcher不执行任何操作
有人在这种情况下成功地进行过单元测试吗?有什么建议或解决办法可以让调度员活下来吗
我知道我可以将回调设置为内部回调,并允许我的单元测试调用此方法,但我不希望更改代码,将此方法作为最后手段。您没有发布测试,因此我不清楚您试图测试什么,但很可能您正在尝试测试以下内容之一:
复合表示事件
//排列
Mock mockEvent=new Mock();
Mock mockAggregator=new Mock();
mockEvent.Setup
(
evnt=>evnt.Subscribe(It.IsAny())
);
mockAggregator.Setup
(
agg=>agg.GetEvent()
.Returns(mockEvent.Object);
);
//表演
MyClassiWantTest目标=新的MyClassiWantTest(mockAggregator.Object);
//断言
mockEvent.VerifyAll();
这是最基本的。这里的经验法则是,如果测试依赖于难以提供的系统资源,请将其与测试隔离
编辑:阅读您的问题后,我看到您正在尝试测试回调。
在这个示例中,我测试“CurrentValueProperty”属性是否设置为回调方法中传递的任何值。以下是该示例:
//Arrange
Mock<MyEvent> mockEvent = new Mock<MyEvent>();
Mock<IEventAggregator> mockAggregator = new Mock<IEventAggregator>();
Action<int> theEventCallback = null;
mockEvent.Setup
(
evnt => evnt.Subscribe(It.IsAny<Action<int>>())
)
.Callback<Action<int>>
(
cb => theEventCallback = cb
);
mockAggregator.Setup
(
agg => agg.GetEvent<MyEvent>()
)
.Returns(mockEvent.Object);
//Act
MyClassIWantToTest target = new MyClassIWantToTest(mockAggregator.Object);
//we expect this to be populated by the callback specified in our mock setup
//that will be triggered when Subscribe is called in
//MyClassIWantToTest's constructor
theEventCallback(27);
//Assert
Assert.AreEqual(target.CurrentValueProperty, 27);
//排列
Mock mockEvent=new Mock();
Mock mockAggregator=new Mock();
动作theEventCallback=null;
mockEvent.Setup
(
evnt=>evnt.Subscribe(It.IsAny())
)
.回拨
(
cb=>theEventCallback=cb
);
mockAggregator.Setup
(
agg=>agg.GetEvent()
)
.Returns(mockEvent.Object);
//表演
MyClassiWantTest目标=新的MyClassiWantTest(mockAggregator.Object);
//我们希望它由模拟设置中指定的回调填充
//这将在调用Subscribe时触发
//MyClassWantTest的构造函数
第七回(27);
//断言
Assert.AreEqual(target.CurrentValueProperty,27);
就是这样。如果您试图对类进行单元测试(而不是CompositePresentationEvent
),那么在测试中引入realCompositePresentationEvent
实例会使它们成为非单元。也许你不应该玩CPE,而应该将你的类与之隔离,然后使用mock/stub?是的,这很公平。我想当我能够模拟这些课程时,我有点陷入了这些课程提出的问题中。我会试试安德森的建议,看看能否解决。谢谢就我努力实现的目标而言,你对第二点的看法是正确的。由于某些原因,我不能使用模拟框架,但我已经有一个模拟事件聚合器,应该能够扩展它来模拟演示事件。谢谢,我会试试的!我能够用类似的方法模拟我正在使用的演示事件——如果有模拟框架会更好though@Scott:我想知道为什么不能使用模拟框架。只是好奇。
//Arrange
Mock<MyEvent> mockEvent = new Mock<MyEvent>();
Mock<IEventAggregator> mockAggregator = new Mock<IEventAggregator>();
Action<int> theEventCallback = null;
mockEvent.Setup
(
evnt => evnt.Subscribe(It.IsAny<Action<int>>())
)
.Callback<Action<int>>
(
cb => theEventCallback = cb
);
mockAggregator.Setup
(
agg => agg.GetEvent<MyEvent>()
)
.Returns(mockEvent.Object);
//Act
MyClassIWantToTest target = new MyClassIWantToTest(mockAggregator.Object);
//we expect this to be populated by the callback specified in our mock setup
//that will be triggered when Subscribe is called in
//MyClassIWantToTest's constructor
theEventCallback(27);
//Assert
Assert.AreEqual(target.CurrentValueProperty, 27);