Tenía que hacer algo similar, así que se me ocurrió una solución para esto.
No es simple, pero una vez que todo está configurado, puede reutilizarlo en todos los proyectos. También tengo una descarga de este código en GitHub (https://github.com/johnkoerner/MSTestLooper), pero en caso de que desaparezca en algún momento, así es como lo hice.
Primero creamos un atributo que aplicaremos a nuestra clase para indicarle que ejecute todas las pruebas varias veces. Haga todo esto en un ensamblaje por separado, porque la DLL necesita vivir en una ubicación especial.
[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);
}
}
A continuación tenemos para crear una prueba personalizada clase de ejecución de clase:
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
}
}
Por último añadimos un invocador costumbre, que es donde se realice el bucle:
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;
}
}
Los HelperTestResults class solo crea cadenas para la salida, puede manejar esto como desee y no quiero incluir ese código porque hará que esta publicación sea mucho más larga.
Compilar esto en un DLL y entonces usted necesita para copiarlo en
C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\PublicAssemblies
También tiene que crear una entrada de registro para la clase:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\11.0\EnterpriseTools\QualityTools\TestTypes\{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}\TestTypeExtensions\TestLooperAttribute]
"AttributeProvider"="TestLooper.TestLooperAttribute, TestLooper"
Ahora que tiene todo eso Hecho, finalmente puede utilizar la clase:
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));
}
}
}
Tenga en cuenta que nuestro método de prueba acepta un parámetro, que viene f rom del looper de prueba. También muestro esto usando una prueba basada en datos, para mostrar que puedes combinar los dos para generar grandes permutaciones en tus conjuntos de datos.
Ni siquiera sabía que MSTest tuviera tanta extensibilidad. Esto es genial, gracias! –