Comment exécuter une méthode de test avec plusieurs paramètres dans MSTest?

140

NUnit a une fonctionnalité appelée Values, comme ci-dessous:

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

Cela signifie que la méthode de test s'exécutera six fois:

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

Nous utilisons MSTest maintenant, mais y a-t-il un équivalent pour que je puisse exécuter le même test avec plusieurs paramètres?

[TestMethod]
public void Mytest()
{
    // ...
}
La lumière
la source
Vous pouvez utiliser MSTestHacks, comme décrit dans la réponse stackoverflow.com/a/19536942/52277 .
Michael Freidgeim
Double
Michael Freidgeim
@MichaelFreidgeim Cette question a de meilleures réponses que votre cible suggérée
Rob
1
@Rob: IMHO, la réponse la plus appropriée -MSTestHacks - Comment RowTest avec MSTest? manque dans cette question.
Michael Freidgeim
@MichaelFreidgeim Peut-être, bien qu'il semble que la fonctionnalité existe depuis 3 ans et demi maintenant ( stackoverflow.com/questions/9021881/… )
Rob

Réponses:

46

Il n'est malheureusement pas pris en charge dans les anciennes versions de MSTest. Apparemment, il existe un modèle d'extensibilité et vous pouvez l'implémenter vous-même . Une autre option serait d'utiliser des tests basés sur les données .

Mon opinion personnelle serait de s'en tenir à NUnit cependant ...

Depuis Visual Studio 2012, mise à jour 1, MSTest a une fonctionnalité similaire. Voir la réponse de McAden .

jeroenh
la source
Nous utilisons Selenium qui génère du code NUnit, nous sommes donc passés à utiliser NUnit à la place :)
The Light
4
J'ai trouvé que quelque chose de similaire est maintenant possible dans Visual Studio 2012 Update 1, juste pour info pour que quiconque examine cette réponse.
McAden
@McAden avez-vous un lien avec une explication?
jeroenh
6
J'ai donné une réponse ci-dessous avec un exemple et un lien vers mon article de blog. Il mentionne les attributs nécessaires ainsi que la propriété "DisplayName" sur l'attribut qui distingue les observations dans l'Explorateur de tests. Il a également été mentionné dans l'annonce d'octobre du CTP (qui a maintenant la version officielle) blogs.msdn.com/b/visualstudioalm/archive/2012/10/26/ ... J'ai ajouté les informations à cette question SO parce que je a passé pas mal de temps à le chercher. Espérons que cela fera gagner du temps à quelqu'un.
McAden
167

EDIT 4 : On dirait que cela est terminé dans MSTest V2 17 juin 2016: https://blogs.msdn.microsoft.com/visualstudioalm/2016/06/17/taking-the-mstest-framework-forward-with-mstest- v2 /

Réponse originale :

Il y a environ une semaine, dans Visual Studio 2012 Update 1, quelque chose de similaire est désormais possible:

[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 );
}

EDIT : Il semble que cela n'est disponible que dans le projet de test unitaire pour WinRT / Metro . Décevant

EDIT 2 : Voici les métadonnées trouvées à l'aide de «Go To Definition» dans 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);
    }
}

EDIT 3 : Ce problème a été soulevé dans les forums UserVoice de Visual Studio. La dernière mise à jour déclare:

DEMARRÉ · L'équipe Visual Studio ADMIN L'équipe Visual Studio (équipe produit, Microsoft Visual Studio) a répondu · 25 avril 2016 Merci pour vos commentaires. Nous avons commencé à travailler là-dessus.

Pratap Lakshman Visual Studio

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

McAden
la source
4
Windows Phone est désormais également pris en charge, avec Visual Studio 2012 Update 2 (actuellement, CTP 4)
Pedro Lamas
8
J'ai la mise à jour 1 mais DataTestMethod et DataRow ne sont pas reconnus, dans quelle bibliothèque se trouvent ces attributs?
DevDave
3
Existe-t-il une source officielle sur DataTestMethod? Dans quel espace de noms se trouve-t-il, dans quel assembly?
Igor Lankin
2
J'ai trouvé que UnitTestFramework.dll était installé sur mon ordinateur et après l'avoir référencé manuellement, j'ai pu écrire une méthode à l'aide de l'attribut [DataTestMethod] avec des lignes de données, mais je ne peux pas obtenir l'Explorateur de tests dans Visual Studio 2012.3 pour trouver la méthode.
Josh DeLong
5
Je suis allé au chemin du fichier "C: \ Program Files (x86) \ Microsoft SDKs \ Windows \ v8.0 \ ExtensionSDKs \ MSTestFramework \ 11.0 \ References \ CommonConfiguration \ neutral \ Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll" sur mon ordinateur et le dossier était là. Je l'ai donc référencé dans mon projet de test unitaire de base. L'ouverture de la dll dans JustDecompile montre que la bibliothèque n'a que des références à mscorlib, System et System.Core. Ce n'est pas un projet du Windows Store.
Josh DeLong
34

Cette fonctionnalité est actuellement en pré-version et fonctionne avec Visual Studio 2015.

Par exemple:

[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
la source
C'est la bonne réponse. Notez qu'il n'est pas nécessaire de dire [DataTestMethod] pour utiliser [DataRow] ( stackoverflow.com/a/59162403/2540235 )
mattavatar
11

Pas exactement les mêmes que les attributs de NUnit Value(ou TestCase), mais MSTest a l' DataSourceattribut, qui vous permet de faire une chose similaire.

Vous pouvez le connecter à une base de données ou à un fichier XML - ce n'est pas aussi simple que la fonctionnalité de NUnit, mais il fait le travail.

km
la source
7

MSTest a un attribut puissant appelé DataSource . En utilisant cela, vous pouvez effectuer des tests basés sur les données comme vous l'avez demandé. Vous pouvez avoir vos données de test au format XML, CSV ou dans une base de données. Voici quelques liens qui vous guideront

Pritam Karmakar
la source
6

C'est très simple à mettre en œuvre - vous devez utiliser la TestContextpropriété et TestPropertyAttribute.

Exemple

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();
    //...
}

ÉDITER:

J'ai préparé quelques méthodes d'extension pour simplifier l'accès à la TestContextpropriété et agir comme si nous avions plusieurs cas de test. Voir l'exemple de traitement des propriétés de test simples ici:

[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);
    });
}

et exemple avec la création d'objets de test complexes:

[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);
        });
}

Jetez un œil aux méthodes d' extension et à l'ensemble d' exemples pour plus de détails.

Andrey Burykin
la source
2
Cette approche fonctionne mais ne crée pas de cas de test individuels pour chaque ensemble de paramètres.
usr4896260
Vous pouvez utiliser quelque chose de plus complexe comme valeur TestProperty (ex. "0-100"), l'analyser et le gérer dans le corps du test.
Andrey Burykin
4

Il existe, bien sûr, une autre façon de faire cela qui n'a pas été discutée dans ce fil, c'est-à-dire par héritage de la classe contenant TestMethod. Dans l'exemple suivant, une seule TestMethod a été définie mais deux cas de test ont été réalisés.

Dans Visual Studio 2012, il crée deux tests dans 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
la source
3

Je n'ai pas pu faire fonctionner The DataRowAttributedans Visual Studio 2015, et c'est ce que j'ai fini avec:

[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 vraie solution ici est d'utiliser simplement NUnit (sauf si vous êtes coincé dans MSTest comme je le suis dans ce cas particulier).

Brandon
la source
3
vous devez diviser chaque appel de test en un test distinct afin de gagner du temps lorsque l'un d'entre eux se cassera. (dont nous savons tous qu'il se produira)
argent
Oui bien sûr. En pratique, c'est ainsi que cela se ferait. Dans ce cas, je ne faisais que l'illustrer par souci de simplicité
Brandon