【问题标题】:Standard .Net TDD Memory Test标准 .Net TDD 内存测试
【发布时间】:2009-02-20 20:37:34
【问题描述】:

编写一个标准化的 TDD [测试] 方法是否有用,这会暴露常见的内存问题?

这组测试可以轻松、快速地应用于一个方法,并且会使“经典”.NET 内存问题失败,但会通过经典解决方案。

例如,常见的内存问题可能是:垃圾收集器重定位过多 ;分配太多;太多的垃圾回收(经典示例更喜欢 StringBuilder 而不是字符串 reallocs );持有内存太久(经典示例调用 dispose 并且不依赖终结器);物体不恰当地到达 g1, g2, LOH ;随着时间的推移,小泄漏会增加一些重要的事情,......等等。

也许代码看起来像这样……

[Test]
public void Verify_MyMethodUnderTest_Is_Unlikely_To_Have_Common_Memory_Problem()
{

//-Setup
var ExpectationToleranceA = ...
var ExpectationToleranceB = ...
...

//-Execute
var MeasurementA = MyClassUnderTest.MyMethodUnderTest( dependancyA ) ; 
var MeasurementB = MyClassUnderTest.MyMethodUnderTest( dependancyB ) ; 
…

//-Verfiy
Assert.That(  MeasurementA  , Is.WithinTolerance( ExpectationToleranceA  ) ) ;
Assert.That(  MeasurementB  , Is.WithinTolerance( ExpectationToleranceB  ) ) ;

}

还有其他关于内存压力问题的帖子,但这里的想法是能够快速将标准测试指向一个方法,并且测试会在常见/经典内存压力问题上失败,但通过常见解决方案绿色通过.然后可能会指示开发人员检查失败的代码并可能修复泄漏、更改容差甚至删除 TDD 内存压力测试。

这个想法有腿吗?

这里有一个与 C++ 应用程序相关的问题,Memory leak detection while running unit tests,这是一个类似的问题,但并不完全相同。 Twk 的问题是指在所有的测试都跑完之后再看内存...

我的想法是让 .NET 1) 对常见内存问题的每种方法进行单元测试 2)失败的经典内存问题 3)通过经典修复经典常见内存问题 4) 能够快速对函数进行快速标准测试,以查看它是否表现出典型症状 5) 能够升级单元测试中应用的Standard TDD .Net Memory Pressure Test。这意味着对上述代码进行重构,以便升级到标准测试将更改升级整个项目的 Nunit 测试套件中应用的内存测试。

(p.s. 我知道没有 Is.WithinTolerance 调用,但我只是在展示一个想法。) 干杯...

【问题讨论】:

    标签: .net unit-testing memory-management memory-leaks


    【解决方案1】:

    单元测试通常最好用于测试小块功能。你所追求的听起来更像是测试整个系统的行为和性能的集成测试。

    我看到这种方法的问题是系统中的任何给定单元都可能不会生成这些与内存相关的错误。因此,即使您可以让这样的东西工作,您也不能保证一旦您的单元作为一个整体工作就不会出现内存问题。

    所以我的建议是在多个状态下进行集成测试。在不同的负载水平下测试系统,看看会出现什么样的内存问题(如果有的话)。这种测试对你会更有益。

    【讨论】:

    • 谢谢。我认为我的想法背后是梳理问题并获得更高质量的功能代码,特别是除了测试业务功能之外的常见内存压力问题。可以说内存问题仅在集成测试时才会出现。
    【解决方案2】:

    好的单元测试应该针对小段代码。理想情况下,它们应该是可重复的,但当涉及垃圾收集器时,情况并非如此。

    尽管如此,您可以使用单元测试框架工具来进行非单元测试(功能测试、回归测试、压力测试等)。但是您需要意识到,您并不是在进行真正的单元测试。所以不要在一些自动构建中使用它们,也不要强迫其他开发人员在他们的提交测试中包含这样的测试。 真正的单元测试可能不会受到非单元测试的影响!

    如果您想做这样的事情,请考虑在您要测试的操作之前和之后调用 GC.Collect() 方法。连续多次调用以更轻松地感知内存消耗的增长。考虑在单独的夜​​间构建中添加此类测试(与实际单元测试分开),因为这可能很耗时。在您可以完全控制的单独机器上调用测试(测试期间带有一些 Flash 动画的打开浏览器或病毒扫描程序可能会弄乱您的结果)。将内存消耗的数字存储在某处以供以后查看。这将使您意识到在较长的开发周期中内存消耗会缓慢增加。

    【讨论】:

    • 是的,GC 是不可预测的,但可能有迹象表明更大的问题,比如对过敏进行皮肤测试。可以对功能进行“皮肤测试”。是的,我的想法不符合 TDD 单元测试的原始想法。在生产之前识别有问题的功能会很有用,...
    【解决方案3】:

    我会说这是个坏主意。如果您想编写“验证”垃圾收集器的某些行为的测试,那么您基本上是在“测试”您无法控制的代码。垃圾收集器的确切行为是当前 CLR 的实现细节。它可能会在未来发生变化,从而导致您的测试“失败”。在大多数情况下,您可能无法更改代码中的任何内容来“修复”测试,因此您不得不更改测试以反映新的实现。在我看来,这用途有限。

    应使用单元测试来验证您自己的代码的意图,以便在更改破坏现有代码时通知您。使用它们来帮助开发和维护您自己的代码。

    根据我的经验,最好的结果是确保单元测试没有依赖关系。进行您描述的那种测试意味着测试将对硬件和运行时系统有很多依赖关系。

    只有我的 5 美分。

    【讨论】:

    • 好点,TDD 建议测试自己的功能。我仍然对函数内的.Net mem“泄漏”或与对其他函数的调用一起感兴趣。一个函数可能会通过通常的单元测试,但由于它导致 .Net 内存“泄漏”而未能达到其目的,那么如何对此进行测试...
    猜你喜欢
    • 2021-02-16
    • 1970-01-01
    • 1970-01-01
    • 2017-08-26
    • 1970-01-01
    • 1970-01-01
    • 2010-11-12
    • 2015-09-06
    • 2023-03-05
    相关资源
    最近更新 更多