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 框架和 LightInject 注入依赖。

所以这让我想到了一个问题,这些测试在现实中有多可靠?

所以我相信我找到了我自己的问题的答案(至少部分):

时间上的差异是因为在通过单元测试进行测量时,只考虑了视图 (xaml + cs) 加载时间。

通过视图构造函数执行此操作时,视图模型也在秒表停止计时之前加载!

要记住的另一件事是构建选项。在不调试的情况下执行单元测试时,时间大大缩短(有问题的视图平均从 128.9 毫秒减少到 90 毫秒)。

即使我相信我找到了答案,我也会留下这个问题,以防有人有比我使用的更好的答案或衡量方法。