草庐IT

c# - 我可以在Visual Studio中为单元测试/负载测试创建自定义TestContext计时器吗?

coder 2024-06-03 原文

我的一些UnitTest具有在循环中定义的Sleep。我不仅要描述测试的每个迭代,还要描述所有迭代的总时间,以显示任何非线性缩放比例。例如,如果我分析“总体”,则它包括 sleep 时间。我可以使用Stopwatch Start/Stop,以便它仅包含doAction()。但是,我无法将秒表结果写入TestContext结果。

[TestMethod]
    public void TestMethod1()
    {
        TestContext.BeginTimer("Overall");
        for (int i = 0; i < 5; i++)
        {
            TestContext.BeginTimer("Per");
            doAction();
            TestContext.EndTimer("Per");
            Sleep(1000);
        }
        TestContext.EndTimer("Overall");
    }

看来TestContext可以继承并重新定义。但是,我看不到任何将其写回到事务存储的示例。

有没有我可以引用的实现或其他想法。我希望在Visual Studio为LoadTest提供的同一份报告中看到它。否则,我必须编写自己的报告。

另外,我尝试嗅探将这些内容写入LoadTest数据库的SQL,但未能成功找出方法。应该有一个SPROC来调用,但是我认为这是测试结束时的所有数据。

最佳答案

好吧,我有一个类似的问题。我想像Visual Studio一样在最终测试结果中报告测试中的一些额外数据/报告/计数器,因此我找到了解决方案。

首先,这无法通过您尝试的方式完成。在存在TestContext的负载测试和单元测试之间没有直接链接。

其次,您必须了解Visual Studio如何创建报告。它从操作系统的performance counters收集数据。您可以编辑这些计数器,删除不需要的计数器,然后添加所需的其他计数器。

如何编辑计数器

负载测试配置有两个关于计数器的基本部分。这些都是:

  • Counter Sets。这些是计数器集,例如默认添加的agent。如果您打开此计数器集,您将看到它收集了诸如内存,处理器,PhysicalDisk e.t.c之类的计数器。因此,在测试结束时,您可以查看所有代理商的所有这些数据。如果要向此计数器集添加更多计数器,则可以双击它(在负载测试编辑器中,请参见下图),然后选择Add Counters。这将打开一个窗口,其中包含系统的所有计数器,然后选择所需的计数器。
  • Counter Set Mappings。在这里,您将计数器集与您的机器关联。默认情况下,[CONTROLLER MACHINE][AGENT MACHINES]带有一些默认计数器集。这意味着映射到[CONTROLLER MACHINE]的计数器集中包含的所有计数器将从您的 Controller 计算机中收集。同样适用于您的所有代理。


  • 您可以添加更多的计数器集和更多的计算机。右键单击Counter Set Mappings-> Manage Counter Sets...,将打开一个新窗口,如下所示:

    如您所见,我添加了另一台名称为db_1的计算机。这是机器的计算机名称,并且必须与 Controller 位于同一域中,才能访问它并收集计数器。我也已将其标记为database server并选择了sql计数器集(sql计数器的默认值,但您可以对其进行编辑并添加所需的任何计数器)。现在,每次执行此负载测试时, Controller 将转到计算机名称为db_1的计算机上,并收集将在最终测试结果中报告的数据。

    现在是编码部分

    好的,在进行了此大介绍之后,该看看如何将数据添加到最终测试结果中了。为此,您必须创建自己的custom performance counters。这意味着必须在收集这些数据所需的计算机中创建一个新的Performance Counter Category。在您的情况下,在您的所有代理中,因为这是执行UnitTests的地方。

    在代理中创建计数器后,可以编辑Agents计数器集,如上所示,并选择其他自定义计数器。

    这是有关如何执行此操作的示例代码。

    首先为您的所有座席创建绩效指标。在每台代理计算机上仅运行一次此代码(或者您可以将其添加到load test plugin):
    void CreateCounter() 
    {
        if (PerformanceCounterCategory.Exists("MyCounters"))
        {
            PerformanceCounterCategory.Delete("MyCounters");
        }
    
        //Create the Counters collection and add your custom counters 
        CounterCreationDataCollection counters = new CounterCreationDataCollection();
        // The name of the counter is Delay
        counters.Add(new CounterCreationData("Delay", "Keeps the actual delay", PerformanceCounterType.AverageCount64));
        // .... Add the rest counters
    
        // Create the custom counter category
        PerformanceCounterCategory.Create("MyCounters", "Custom Performance Counters", PerformanceCounterCategoryType.MultiInstance, counters);
    }
    

    这是您测试的代码:
    [TestClass]
    public class UnitTest1
    {
        PerformanceCounter OverallDelay;
        PerformanceCounter PerDelay;
    
        [ClassInitialize]
        public static void ClassInitialize(TestContext TestContext)
        {
            // Create the instances of the counters for the current test
            // Initialize it here so it will created only once for this test class
            OverallDelay= new PerformanceCounter("MyCounters", "Delay", "Overall", false));
            PerDelay= new PerformanceCounter("MyCounters", "Delay", "Per", false));
            // .... Add the rest counters instances
        }
    
        [ClassCleanup]
        public void CleanUp()
        {
            // Reset the counters and remove the counter instances
            OverallDelay.RawValue = 0;
            OverallDelay.EndInit();
            OverallDelay.RemoveInstance();
            OverallDelay.Dispose();
            PerDelay.RawValue = 0;
            PerDelay.EndInit();
            PerDelay.RemoveInstance();
            PerDelay.Dispose();
        }
    
        [TestMethod]
        public void TestMethod1()
        {
             // Use stopwatch to keep track of the the delay
             Stopwatch overall = new Stopwatch();
             Stopwatch per = new Stopwatch();
    
             overall.Start();
    
             for (int i = 0; i < 5; i++)
             {
                 per.Start();
                 doAction();
                 per.Stop();
    
                 // Update the "Per" instance of the "Delay" counter for each doAction on every test
                 PerDelay.Incerement(per.ElapsedMilliseconds);
                 Sleep(1000);
    
                 per.Reset();
             }
    
             overall.Stop();
    
             // Update the "Overall" instance of the "Delay" counter on every test
             OverallDelay.Incerement(overall.ElapsedMilliseconds);
         }
    }
    

    现在,当您执行测试时,它们将向计数器报告其数据。在负载测试结束时,您将能够看到每台代理计算机中的计数器并将其添加到图形中。将使用MIN,MAX和AVG值进行报告。

    结论
  • 我认为(经过数月的研究),这是将测试中的自定义数据添加到最终负载测试报告中的唯一方法。
  • 似乎很难做到这一点。好吧,如果您理解了这一点,则对其进行优化并不困难。我将此功能包装在一个类中,以便于初始化,更新和管理计数器。
  • 这是非常非常有用的。现在,我可以从测试中看到统计信息,即使用默认计数器是不可能的。这样的我们,当对Web服务的Web请求失败时,我可以捕获该错误并更新相应的计数器(例如,超时,ServiceUnavailable,RequestRejected ...)。

  • 希望我能帮上忙。 :)

    关于c# - 我可以在Visual Studio中为单元测试/负载测试创建自定义TestContext计时器吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16901453/

    有关c# - 我可以在Visual Studio中为单元测试/负载测试创建自定义TestContext计时器吗?的更多相关文章

    1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    2. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    3. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

      使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

    4. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

      查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

    5. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

      我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

    6. ruby - Ruby 的 Hash 在比较键时使用哪种相等性测试? - 2

      我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。

    7. ruby - RSpec - 使用测试替身作为 block 参数 - 2

      我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

    8. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

      我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

    9. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

      我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

    10. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

      Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

    随机推荐