有没有办法计算测试方法的流逝时间,忽略初始化时间?

这是一个踩在StackOverflow和SuperUser之间的灰色区域的问题。 由于我怀疑答案可能涉及与代码相关的解决方案,例如创意使用StopWatch ,我会在这里提出。

我正在使用Visual Studio 2013对依赖于entity framework数据模型的控制器执行unit testing。 测试资源管理器很好地在一个简短的列表中显示我的测试结果以及它们的经过时间。

不过,我发现我的控制器unit testing时间比我预期的要长得多。 我开始怀疑这是由于我用来创建一个模拟的初始化代码(使用Moq,但这没关系)实体模型。

果然,显示初始化例程包含在经过的时间中是一件小事。

 [TestClass] public class InitializeTest { [TestInitialize] public void Initialize() { Thread.Sleep(10000); } [TestMethod] public void TestInitializeRuntime() { Assert.Inconclusive(); } } 

这在测试资源管理器中产生了以下输出:

Test Explorer的屏幕截图

这使得由我的模拟实体模型支持的测试所用的时间相当无用,因为初始化代码通常消耗大于测试所用时间的95%。 每种方法看起来都很慢,实际上它们并非如此。

是否有替代配置或某些创造性使用代码(如前面提到的StopWatch ),这将允许我仅报告测试方法的耗用时间,不包括初始化或清理测试所花费的时间?

我今天发现了一种在MSTest中处理昂贵初始化的方法,而不会导致测试报告缓慢。 我发布这个答案是为了考虑而不接受它,因为它确实有一个适度的代码气味。

每次运行测试时,MSTest都会创建测试类的新实例。 由于这种行为,每个测试都会在实例构造函数中编写一次代码。 这与[TestInitialize]方法类似,但有一个例外:MSTest 创建测试类的实例之后和执行[TestInitialize]例程之前开始计时unit testing。

由于这种特定于MSTest的行为,可以在构造函数中放置应该从自动生成的时序统计信息中省略的初始化代码。

为了certificate我的意思,请考虑以下测试和生成的输出。

测试:

 public class ConstructorTest { public ConstructorTest() { System.Threading.Thread.Sleep(10000); } [TestMethod] public void Index() { } [TestMethod] public void About() { } } 

输出:

结果截图

我的想法:

上面的代码肯定会产生我正在寻找的效果; 但是,虽然使用构造函数或[TestInitialize]方法来处理初始化似乎是安全的 ,但我必须假设后者存在于此框架中是有充分理由的。

可能存在这样的情况:在计算中包括初始化时间的报告可能是有用的,例如在估计应该预期大量测试应该消耗多少实时时。

Rich Turner关于时间敏感操作应该如何使用断言停止监视的讨论也值得认可(并且有我的投票)。 另一方面,我将Visual Studio提供的自动生成的时序报告看作是一种有用的工具,用于识别失控的测试,而无需在每次测试中编写定时样板代码。

总而言之,我很高兴找到了解决方案,并欣赏这里讨论的替代方案。

干杯!

您的测试应该旨在回答问题。 问题如下:1。我的代码是否按预期运行? 2.我的代码是否按预期执行?

但是,不要依赖测试框架的内部工作来为代码计时(特别是不适合的任务),而是编写测试来测试特定代码和/或例程的性能。

例如,您可以编写一个测试方法,该方法可以启动秒表,执行一些工作,停止秒表并测量操作所需的时间。 然后你应该断言测试没有超过预期的最大持续时间,如果确实如此,你会认为它是一个失败的测试。

这样您就不会测量测试基础架构的不可预测性能,而是实际测试代码的性能。

此外,正如Aravol建议的那样,您可以通过在静态构造函数中填充Moq来预先加载测试设置的成本,因为静态构造函数在执行任何new编辑或实例方法之前执行。

您遇到的问题是unit testing不允许更改时间或输出数据 – 它们只是执行和完成。

您可以这样做的一种方法是违反unit testing标准并使用静态引用和静态构造函数来准备您的后备数据 – 虽然在技术上没有保证,VS 2013会在同一AppDomain中执行所有unit testing(尽管通过给定的单独实例) TestClass

我不相信有很多实例需要冗长的测试初始化​​。 知道海报的例子中包含了哪种操作会很有趣。

将TestInit的函数分成ClassInit需要一点创造力(之前有人建议使用构造函数……有点相同的东西,但是代码块中的错误会报告完全不同)。 例如,如果每个测试都需要从文件中读取的List <>字符串,则将其拆分为:

1)ClassInit – 读取文件,将字符串捕获到数组中(慢速部分)2)TestInit – 将数组的元素复制到每个测试可访问的List <>(快速部分)

我反对使用静态来试图解决测试性能问题,它会破坏每个测试的相互隔离。

我也反对使用像StopWatches这样的东西来测试他们自己的性能…运行测试生成一个报告,因此该报告的观察者应该识别运行时间太长的测试。 此外,如果我们想要自动化测试来运用某些东西的性能,那不是unit testing,那就是性能测试,它可以(应该?)完全不同。