English 中文(简体)
Repeat mstest test run multiple times
原标题:
  • 时间:2009-05-16 15:50:21
  •  标签:
  • .net
  • mstest

Some of my mstest unit tests help detect multi-threading race conditions, and as such they are most useful when run many times in a row, but I only want to do this for specific test runs -- not all the time.

Is there a way to configure mstest (in the Test List Editor preferably) to run a test multiple times?

最佳回答

I needed to do something similar, so I came up with a solution to this.

It s not simple, but once everything is setup you can reuse it across projects. I also have a download of this code on GitHub (https://github.com/johnkoerner/MSTestLooper), but in case that goes away at some point, here is how I did it.

First we create an attribute that we will apply to our class to tell it run all the tests multiple times. Do all of this in a separate assembly, because the DLL needs to live in a special location.

[Serializable]
public class TestLooperAttribute :  TestClassExtensionAttribute
{
    private static readonly Uri thisGuy = new Uri("urn:TestLooperAttribute");

    private string _PropertyName;
    public string PropertyName
    {
        get
        { return _PropertyName; }
        set
        {
            _PropertyName = value;
        }
    }
    public override Uri ExtensionId
    {

        get {
            return thisGuy; }
    }


        public override TestExtensionExecution GetExecution()
    {

        return new TestLooperExecution(PropertyName);
    }
}

Next we have to create a custom test class execution class:

class TestLooperExecution : TestExtensionExecution
{
    private string PropertyName;

    public TestLooperExecution(string PropertyName)
    {
        this.PropertyName = PropertyName;
    }

    public override ITestMethodInvoker CreateTestMethodInvoker(TestMethodInvokerContext InvokerContext)
    {
        return new TestLooperInvoker(InvokerContext, PropertyName);
    }

    public override void Dispose()
    {
        //TODO: Free, release or reset native resources
    }

    public override void Initialize(TestExecution Execution)
    {
        //TODO: Wire up event handlers for test events if needed

    }
}

Finally we add a custom invoker, which is where we perform the looping:

class TestLooperInvoker : ITestMethodInvoker
{
    private TestMethodInvokerContext m_invokerContext;
    private string PropertyName;

    public TestLooperInvoker(TestMethodInvokerContext InvokerContext, string PropertyName)
    {
        m_invokerContext = InvokerContext;
        this.PropertyName = PropertyName;
    }

    public TestMethodInvokerResult Invoke(params object[] args)
    {

        // Our helper results class to aggregate our test results
        HelperTestResults results = new HelperTestResults();

        IEnumerable<object> objects = m_invokerContext.TestContext.Properties[PropertyName] as IEnumerable<object>;

        foreach (var d in objects)
            results.AddTestResult(m_invokerContext.InnerInvoker.Invoke(d), new object[1] { d.GetType().ToString()});

        var output = results.GetAllResults();
        m_invokerContext.TestContext.WriteLine(output.ExtensionResult.ToString());

        return output;
    }
}

The HelperTestResults class just builds up strings for output, you can handle this how you want and I don t want to include that code because it will just make this post that much longer.

Compile this into a DLL and then you need to copy it to

C:Program Files (x86)Microsoft Visual Studio 11.0Common7IDEPublicAssemblies

You also have to create a registry entry for the class:

Windows Registry Editor Version 5.00 
[HKEY_LOCAL_MACHINESOFTWAREWow6432NodeMicrosoftVisualStudio11.0EnterpriseToolsQualityToolsTestTypes{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}TestTypeExtensionsTestLooperAttribute]
"AttributeProvider"="TestLooper.TestLooperAttribute, TestLooper"

Now that you have all of that done, you can finally use the class:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestLooper;
using System.Collections.Generic;
namespace UnitTestSamples
{
    [TestLooper(PropertyName="strings")]
    public class UnitTest1
    {
        public static List<String> strings = new List<String>();
        private TestContext testContextInstance;

        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }
        [ClassInitialize()]
        public static void Init(TestContext x)
        {
            strings.Add("A");
            strings.Add("B");
            strings.Add("C");
            strings.Add("D");

        }

        [TestInitialize()]
        public void TestInit()
        {
            if (!TestContext.Properties.Contains("strings"))
            testContextInstance.Properties.Add("strings", strings);
        }

        [TestMethod]
        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "DataDriven1.csv", "DataDriven1#csv", DataAccessMethod.Sequential)]
        [DeploymentItem("DataDriven1.csv")]
        public void TestMethodStrings(string s)

        {
            int value1 = Convert.ToInt32(TestContext.DataRow["Col1"]); ;
            TestContext.WriteLine(String.Format("{0}:{1}", s, value1));
        }
    }
}

Notice that our test method accepts a parameter, which comes from the test looper. I also show this using a data driven test, to show you can combine the two together to generate large permutations across your data sets.

问题回答
[TestMethod()]
public void RepetableTest(){
   for(int i = 0; i < repeatNumber; i++){

     //test code goes here


   }
}

Consider creating a test to spin off a couple of threads. The Test List won t allow you to have multiple entries for the same test. You could assign, however, the multi-threaded test to its own list and call it only when you want to run that particular test.

I guess the answer is no.

You can create custom attribute that yields data rows specified number of times. Idea is taken from https://learn.microsoft.com/en-us/visualstudio/test/how-to-create-a-data-driven-unit-test?view=vs-2022 Example attribute class:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace EndToEndTest.Infrastructure;

public class RepeatAttribute : Attribute, ITestDataSource {
private readonly int _count;

public RepeatAttribute(int count = 10) {
    this._count = count;
}

public IEnumerable<object[]> GetData(MethodInfo methodInfo) {
    return Enumerable.Range(1, _count).Select(x => new object[0]);
}

public string GetDisplayName(MethodInfo methodInfo, object[] data) {
    if (data != null) {
        return string.Format(CultureInfo.CurrentCulture, "{0} x{1}", methodInfo.Name, _count);
    }

    return null;
}
}

And then add this attribute to a test method

    [TestMethod]
    [Repeat(5)]
    public void TestAccountSummaryInitialData() {...}




相关问题
Manually implementing high performance algorithms in .NET

As a learning experience I recently tried implementing Quicksort with 3 way partitioning in C#. Apart from needing to add an extra range check on the left/right variables before the recursive call, ...

Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

How do I compare two decimals to 10 decimal places?

I m using decimal type (.net), and I want to see if two numbers are equal. But I only want to be accurate to 10 decimal places. For example take these three numbers. I want them all to be equal. 0....

Exception practices when creating a SynchronizationContext?

I m creating an STA version of the SynchronizationContext for use in Windows Workflow 4.0. I m wondering what to do about exceptions when Post-ing callbacks. The SynchronizationContext can be used ...

Show running instance in single instance application

I am building an application with C#. I managed to turn this into a single instance application by checking if the same process is already running. Process[] pname = Process.GetProcessesByName("...

How to combine DataTrigger and EventTrigger?

NOTE I have asked the related question (with an accepted answer): How to combine DataTrigger and Trigger? I think I need to combine an EventTrigger and a DataTrigger to achieve what I m after: when ...

热门标签