WPF 中的单元测试视图渲染时间
Unit test view rendering time in WPF
我对我的项目有一个要求,所有视图都应该在 500 毫秒内呈现自己,这没有考虑在视图上绑定数据所花费的时间 and/or 执行对后端的调用。
只是应该测量控件渲染时间。
我看到 many similar questions here in SO 和其他地方,但 none 确实帮助我解决了这个问题,因为他们建议在测试之外使用分析器或代码。
到目前为止我有以下单元测试:
[TestMethod]
public void View_WaitForLoadedEvent_ElapsedTimeDoesNotExceedAllowedLimit()
{
// Arrange.
var dispatcherAction =
new System.Action(() =>
{
this.stopWatch.Stop();
this.elapsedMilliseconds = this.stopWatch.ElapsedMilliseconds;
Dispatcher.ExitAllFrames();
});
this.stopWatch.Start();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Loaded, dispatcherAction);
// Act.
var view = new HomeView();
Dispatcher.Run();
// Assert.
Assert.IsTrue(this.elapsedMilliseconds < RenderTimeTests.MaxAllowedRenderingMilliseconds,
RenderTimeTests.GetFormattedErrorMessage(view.ToString(), this.elapsedMilliseconds));
}
现在,在连续执行该测试 10 次后,我得到了 this.elapsedMilliseconds
变量的以下值:
153、140、109、144、131、116、124、127、139、106。
所以平均加载需要 128.9 毫秒。
这些值相当恒定,但是在 Whosebug 中针对类似问题的大多数答案中推荐的测试时,这些值是不同的。
推荐测试如下:
public HomeView()
{
var sw = new Stopwatch();
sw.Start();
this.Dispatcher.BeginInvoke(
DispatcherPriority.Loaded,
new System.Action(() =>
{
sw.Stop();
MessageBox.Show("Took " + sw.ElapsedMilliseconds + " ms");
}));
this.InitializeComponent();
}
这会在消息框上显示以下值:
206、213、218、203、210、209、210、210、222、230。平均为 213.1。
看起来可能没有那么多,但这些值告诉我实际渲染时间比自动化测试告诉我的时间高 60%!
最后,我决定删除 MessageBox.Show(...)
方法并用 Debug.WriteLine(...)
替换它只是为了看看是否有任何区别(虽然此时手表应该不再计数了)并且我得到以下值:
207, 194, 212, 207, 211, 201, 217, 215, 214, 214。给出平均 209.2,比单元测试结果更接近其他执行。
应用程序正在使用 Caliburn.Micro
mvvm 框架和 LightInject
注入依赖。
所以这让我想到了一个问题,这些测试在现实中有多可靠?
所以我相信我找到了我自己的问题的答案(至少部分):
时间上的差异是因为在通过单元测试进行测量时,只考虑了视图 (xaml + cs) 加载时间。
通过视图构造函数执行此操作时,视图模型也在秒表停止计时之前加载!
要记住的另一件事是构建选项。在不调试的情况下执行单元测试时,时间大大缩短(有问题的视图平均从 128.9 毫秒减少到 90 毫秒)。
即使我相信我找到了答案,我也会留下这个问题,以防有人有比我使用的更好的答案或衡量方法。
我对我的项目有一个要求,所有视图都应该在 500 毫秒内呈现自己,这没有考虑在视图上绑定数据所花费的时间 and/or 执行对后端的调用。
只是应该测量控件渲染时间。
我看到 many similar questions here in SO 和其他地方,但 none 确实帮助我解决了这个问题,因为他们建议在测试之外使用分析器或代码。
到目前为止我有以下单元测试:
[TestMethod]
public void View_WaitForLoadedEvent_ElapsedTimeDoesNotExceedAllowedLimit()
{
// Arrange.
var dispatcherAction =
new System.Action(() =>
{
this.stopWatch.Stop();
this.elapsedMilliseconds = this.stopWatch.ElapsedMilliseconds;
Dispatcher.ExitAllFrames();
});
this.stopWatch.Start();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Loaded, dispatcherAction);
// Act.
var view = new HomeView();
Dispatcher.Run();
// Assert.
Assert.IsTrue(this.elapsedMilliseconds < RenderTimeTests.MaxAllowedRenderingMilliseconds,
RenderTimeTests.GetFormattedErrorMessage(view.ToString(), this.elapsedMilliseconds));
}
现在,在连续执行该测试 10 次后,我得到了 this.elapsedMilliseconds
变量的以下值:
153、140、109、144、131、116、124、127、139、106。 所以平均加载需要 128.9 毫秒。
这些值相当恒定,但是在 Whosebug 中针对类似问题的大多数答案中推荐的测试时,这些值是不同的。
推荐测试如下:
public HomeView()
{
var sw = new Stopwatch();
sw.Start();
this.Dispatcher.BeginInvoke(
DispatcherPriority.Loaded,
new System.Action(() =>
{
sw.Stop();
MessageBox.Show("Took " + sw.ElapsedMilliseconds + " ms");
}));
this.InitializeComponent();
}
这会在消息框上显示以下值:
206、213、218、203、210、209、210、210、222、230。平均为 213.1。
看起来可能没有那么多,但这些值告诉我实际渲染时间比自动化测试告诉我的时间高 60%!
最后,我决定删除 MessageBox.Show(...)
方法并用 Debug.WriteLine(...)
替换它只是为了看看是否有任何区别(虽然此时手表应该不再计数了)并且我得到以下值:
207, 194, 212, 207, 211, 201, 217, 215, 214, 214。给出平均 209.2,比单元测试结果更接近其他执行。
应用程序正在使用 Caliburn.Micro
mvvm 框架和 LightInject
注入依赖。
所以这让我想到了一个问题,这些测试在现实中有多可靠?
所以我相信我找到了我自己的问题的答案(至少部分):
时间上的差异是因为在通过单元测试进行测量时,只考虑了视图 (xaml + cs) 加载时间。
通过视图构造函数执行此操作时,视图模型也在秒表停止计时之前加载!
要记住的另一件事是构建选项。在不调试的情况下执行单元测试时,时间大大缩短(有问题的视图平均从 128.9 毫秒减少到 90 毫秒)。
即使我相信我找到了答案,我也会留下这个问题,以防有人有比我使用的更好的答案或衡量方法。