¿Cómo podemos ejecutar un método de prueba con múltiples parámetros en MSTest?

140

NUnit tiene una característica llamada Valores, como a continuación:

[Test]
public void MyTest(
    [Values(1,2,3)] int x,
    [Values("A","B")] string s)
{
    // ...
}

Esto significa que el método de prueba se ejecutará seis veces:

MyTest(1, "A")
MyTest(1, "B")
MyTest(2, "A")
MyTest(2, "B")
MyTest(3, "A")
MyTest(3, "B")

Estamos usando MSTest ahora, pero ¿hay algún equivalente para esto para que pueda ejecutar la misma prueba con múltiples parámetros?

[TestMethod]
public void Mytest()
{
    // ...
}
La luz
fuente
Puede usar MSTestHacks, como se describe en la respuesta stackoverflow.com/a/19536942/52277 .
Michael Freidgeim
Posible duplicado de Cómo RowTest con MSTest?
Michael Freidgeim
@MichaelFreidgeim Esta pregunta tiene mejores respuestas que su objetivo sugerido
Rob
1
@Rob: En mi humilde opinión, la respuesta más adecuada -MSTestHacks - ¿Cómo RowTest con MSTest? falta en esta pregunta
Michael Freidgeim
@MichaelFreidgeim Quizás, aunque parece que la funcionalidad existe desde hace 3 años y medio ( stackoverflow.com/questions/9021881/… )
Rob

Respuestas:

46

Desafortunadamente, no es compatible con versiones anteriores de MSTest. Aparentemente hay un modelo de extensibilidad y puede implementarlo usted mismo . Otra opción sería utilizar pruebas basadas en datos .

Sin embargo, mi opinión personal sería seguir con NUnit ...

A partir de Visual Studio 2012, actualización 1, MSTest tiene una característica similar. Ver la respuesta de McAden .

jeroenh
fuente
Estamos usando Selenium que genera el código NUnit, así que cambiamos para usar NUnit en su lugar :)
The Light
44
Descubrí que ahora es posible algo similar en Visual Studio 2012 Update 1, solo para su información para la consideración futura de cualquiera que esté mirando esta respuesta.
McAden
@McAden ¿tienes un enlace con una explicación?
jeroenh
66
Di una respuesta a continuación con un ejemplo y un enlace a mi publicación de blog. Menciona los atributos necesarios y también la propiedad "DisplayName" en el atributo que distingue los casos en el Explorador de pruebas. También se mencionó en el anuncio de octubre del CTP (que ahora tiene el lanzamiento oficial) blogs.msdn.com/b/visualstudioalm/archive/2012/10/26/ ... He agregado la información a esta pregunta SO porque Pasé bastante tiempo buscándolo. Esperemos que esto ahorre algo de tiempo a alguien.
McAden
167

EDITAR 4 : Parece que esto se completa en MSTest V2 17 de junio de 2016: https://blogs.msdn.microsoft.com/visualstudioalm/2016/06/17/taking-the-mstest-framework-forward-with-mstest- v2 /

Respuesta original :

Desde hace aproximadamente una semana en Visual Studio 2012 Update 1, algo similar ahora es posible:

[DataTestMethod]
[DataRow(12,3,4)]
[DataRow(12,2,6)]
[DataRow(12,4,3)]
public void DivideTest(int n, int d, int q)
{
  Assert.AreEqual( q, n / d );
}

EDITAR : Parece que esto solo está disponible dentro del proyecto de prueba de unidad para WinRT / Metro . Gorrón

EDITAR 2 : Los siguientes son los metadatos encontrados usando "Ir a la definición" dentro de Visual Studio:

#region Assembly Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll, v11.0.0.0
// C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\MSTestFramework\11.0\References\CommonConfiguration\neutral\Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll
#endregion

using System;

namespace Microsoft.VisualStudio.TestPlatform.UnitTestFramework
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class DataTestMethodAttribute : TestMethodAttribute
    {
        public DataTestMethodAttribute();

        public override TestResult[] Execute(ITestMethod testMethod);
    }
}

EDITAR 3 : Este problema se mencionó en los foros UserVoice de Visual Studio. Última actualización dice:

INICIADO · Equipo de Visual Studio ADMIN El equipo de Visual Studio (Equipo de producto, Microsoft Visual Studio) respondió · 25 de abril de 2016 Gracias por los comentarios. Hemos empezado a trabajar en esto.

Pratap Lakshman Visual Studio

https://visualstudio.uservoice.com/forums/330519-team-services/suggestions/3865310-allow-use-of-datatestmethod-datarow-in-all-unit

McAden
fuente
44
Windows Phone ahora también es compatible, con Visual Studio 2012 Update 2 (actualmente, CTP 4)
Pedro Lamas
8
Tengo la actualización 1 pero DataTestMethod y DataRow no se reconocen, ¿en qué biblioteca están estos atributos?
DevDave
3
¿Hay alguna fuente oficial sobre DataTestMethod? ¿En qué espacio de nombre está, qué ensamblaje?
Igor Lankin
2
Descubrí que UnitTestFramework.dll estaba instalado en mi computadora y después de hacer una referencia manual, pude escribir un método usando el atributo [DataTestMethod] con filas de datos, pero no puedo obtener el Explorador de pruebas en Visual Studio 2012.3 para encontrar el método.
Josh DeLong
55
Fui a la ruta del archivo "C: \ Archivos de programa (x86) \ Microsoft SDKs \ Windows \ v8.0 \ ExtensionSDKs \ MSTestFramework \ 11.0 \ References \ CommonConfiguration \ neutral \ Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll" en mi computadora y el archivo estaba ahí. Así que lo mencioné en mi proyecto de prueba de unidad básica. Abrir la dll en JustDecompile muestra que la biblioteca solo tiene referencias a mscorlib, System y System.Core. No es un proyecto de la Tienda Windows.
Josh DeLong
34

Esta característica está en prelanzamiento ahora y funciona con Visual Studio 2015.

Por ejemplo:

[TestClass]
public class UnitTest1
{
    [DataTestMethod]
    [DataRow(1, 2, 2)]
    [DataRow(2, 3, 5)]
    [DataRow(3, 5, 8)]
    public void AdditionTest(int a, int b, int result)
    {
        Assert.AreEqual(result, a + b);
    }
}
Pompair
fuente
Esta es la respuesta correcta. Tenga en cuenta que no es necesario decir [DataTestMethod] para usar [DataRow] ( stackoverflow.com/a/59162403/2540235 )
mattavatar
11

No es exactamente lo mismo que los atributos de NUnit Value(o TestCase), pero MSTest tiene el DataSourceatributo, que le permite hacer algo similar.

Puede conectarlo a la base de datos o al archivo XML; no es tan sencillo como la función de NUnit, pero hace el trabajo.

km
fuente
6

Es muy sencillo de implementar: debe usar la TestContextpropiedad y TestPropertyAttribute.

Ejemplo

public TestContext TestContext { get; set; }
private List<string> GetProperties()
{
    return TestContext.Properties
        .Cast<KeyValuePair<string, object>>()
        .Where(_ => _.Key.StartsWith("par"))
        .Select(_ => _.Value as string)
        .ToList();
}

//usage
[TestMethod]
[TestProperty("par1", "http://getbootstrap.com/components/")]
[TestProperty("par2", "http://www.wsj.com/europe")]
public void SomeTest()
{
    var pars = GetProperties();
    //...
}

EDITAR:

Preparé algunos métodos de extensión para simplificar el acceso a la TestContextpropiedad y actuar como si tuviéramos varios casos de prueba. Vea el ejemplo con el procesamiento de propiedades de prueba simples aquí:

[TestMethod]
[TestProperty("fileName1", @".\test_file1")]
[TestProperty("fileName2", @".\test_file2")]
[TestProperty("fileName3", @".\test_file3")]
public void TestMethod3()
{
    TestContext.GetMany<string>("fileName").ForEach(fileName =>
    {
        //Arrange
        var f = new FileInfo(fileName);

        //Act
        var isExists = f.Exists;

        //Asssert
        Assert.IsFalse(isExists);
    });
}

y ejemplo con la creación de objetos de prueba complejos:

[TestMethod]
//Case 1
[TestProperty(nameof(FileDescriptor.FileVersionId), "673C9C2D-A29E-4ACC-90D4-67C52FBA84E4")]
//...
public void TestMethod2()
{
    //Arrange
    TestContext.For<FileDescriptor>().Fill(fi => fi.FileVersionId).Fill(fi => fi.Extension).Fill(fi => fi.Name).Fill(fi => fi.CreatedOn, new CultureInfo("en-US", false)).Fill(fi => fi.AccessPolicy)
        .ForEach(fileInfo =>
        {
            //Act
            var fileInfoString = fileInfo.ToString();

            //Assert
            Assert.AreEqual($"Id: {fileInfo.FileVersionId}; Ext: {fileInfo.Extension}; Name: {fileInfo.Name}; Created: {fileInfo.CreatedOn}; AccessPolicy: {fileInfo.AccessPolicy};", fileInfoString);
        });
}

Eche un vistazo a los métodos de extensión y al conjunto de muestras para obtener más detalles.

Andrey Burykin
fuente
2
Este enfoque funciona pero no crea casos de prueba individuales para cada conjunto de parámetros.
usr4896260
Puede usar algo más complejo como el valor de TestProperty (ej. "0-100"), analizarlo y manejarlo en el cuerpo de la prueba.
Andrey Burykin
4

Por supuesto, hay otra forma de hacer esto que no se ha discutido en este hilo, es decir, a través de la herencia de la clase que contiene el TestMethod. En el siguiente ejemplo, solo se ha definido un TestMethod pero se han realizado dos casos de prueba.

En Visual Studio 2012, crea dos pruebas en el TestExplorer:

  1. DemoTest_B10_A5.test
  2. DemoTest_A12_B4.test

    public class Demo
    {
        int a, b;
    
        public Demo(int _a, int _b)
        {
            this.a = _a;
            this.b = _b;
        }
    
        public int Sum()
        {
            return this.a + this.b;
        }
    }
    
    public abstract class DemoTestBase
    {
        Demo objUnderTest;
        int expectedSum;
    
        public DemoTestBase(int _a, int _b, int _expectedSum)
        {
            objUnderTest = new Demo(_a, _b);
            this.expectedSum = _expectedSum;
        }
    
        [TestMethod]
        public void test()
        {
            Assert.AreEqual(this.expectedSum, this.objUnderTest.Sum());
        }
    }
    
    [TestClass]
    public class DemoTest_A12_B4 : DemoTestBase
    {
        public DemoTest_A12_B4() : base(12, 4, 16) { }
    }
    
    public abstract class DemoTest_B10_Base : DemoTestBase
    {
        public DemoTest_B10_Base(int _a) : base(_a, 10, _a + 10) { }
    }
    
    [TestClass]
    public class DemoTest_B10_A5 : DemoTest_B10_Base
    {
        public DemoTest_B10_A5() : base(5) { }
    }
Soumya Dutta
fuente
3

No pude hacer que The DataRowAttributefuncionara en Visual Studio 2015, y esto es lo que terminé con:

[TestClass]
public class Tests
{
    private Foo _toTest;

    [TestInitialize]
    public void Setup()
    {
        this._toTest = new Foo();
    }

    [TestMethod]
    public void ATest()
    {
        this.Perform_ATest(1, 1, 2);
        this.Setup();

        this.Perform_ATest(100, 200, 300);
        this.Setup();

        this.Perform_ATest(817001, 212, 817213);
        this.Setup();
    }

    private void Perform_ATest(int a, int b, int expected)
    {
        // Obviously this would be way more complex...

        Assert.IsTrue(this._toTest.Add(a,b) == expected);
    }
}

public class Foo
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}

La solución real aquí es usar NUnit (a menos que esté atascado en MSTest como lo estoy en esta instancia en particular).

Brandon
fuente
3
debe dividir cada llamada de prueba en una prueba separada para ahorrar tiempo cuando una de ellas se rompa. (que todos sabemos que sucederá)
plata
Sí, por supuesto. En la práctica así es como se haría. En este caso, solo lo estaba ilustrando por simplicidad
Brandon