Come possiamo eseguire un metodo di test con più parametri in MSTest?


140

NUnit ha una funzione chiamata Valori, come di seguito:

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

Ciò significa che il metodo di prova verrà eseguito sei volte:

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

Stiamo usando MSTest ora, ma esiste un equivalente per questo in modo che io possa eseguire lo stesso test con più parametri?

[TestMethod]
public void Mytest()
{
    // ...
}

È possibile utilizzare MSTestHacks, come descritto in stackoverflow.com/a/19536942/52277 risposta.
Michael Freidgeim,


@MichaelFreidgeim Questa domanda ha risposte migliori del target suggerito
Rob

1
@Rob: IMHO, la risposta più appropriata -MSTestHacks - Come RowTest con MSTest? manca in questa domanda.
Michael Freidgeim

@MichaelFreidgeim Forse, anche se sembra che la funzionalità esista ormai da 3 anni e mezzo ( stackoverflow.com/questions/9021881/… )
Rob

Risposte:


46

Purtroppo non è supportato nelle versioni precedenti di MSTest. Apparentemente esiste un modello di estensibilità e puoi implementarlo da solo . Un'altra opzione sarebbe quella di utilizzare test basati sui dati .

La mia opinione personale sarebbe quella di restare con NUnit però ...

A partire da Visual Studio 2012, aggiornamento 1, MSTest ha una funzionalità simile. Vedi la risposta di McAden .


Stiamo usando il selenio che genera il codice NUnit, quindi invece abbiamo usato NUnit :)
The Light

4
Ho scoperto che qualcosa di simile è ora possibile in Visual Studio 2012 Update 1, solo FYI per la futura considerazione di chiunque stia guardando questa risposta.
McAden,

@McAden hai un link con una spiegazione?
jeroenh,

6
Ho dato una risposta di seguito con un esempio e un link al mio post sul blog. Menziona gli attributi necessari e anche la proprietà "DisplayName" sull'attributo che distingue i casi in Test Explorer. È stato anche menzionato nell'annuncio di ottobre del CTP (che ora ha la versione ufficiale) blogs.msdn.com/b/visualstudioalm/archive/2012/10/26/… Ho aggiunto le informazioni a questa domanda SO perché ho trascorso un bel po 'di tempo a cercarlo. Spero che questo salverà qualcuno un po 'di tempo.
McAden,

167

EDIT 4 : Sembra che questo sia completato in MSTest V2 il 17 giugno 2016: https://blogs.msdn.microsoft.com/visualstudioalm/2016/06/17/taking-the-mstest-framework-forward-with-mstest- v2 /

Risposta originale :

Circa una settimana fa in Visual Studio 2012 Update 1 è ora possibile qualcosa di simile:

[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 : sembra che questo sia disponibile solo all'interno del progetto di unit testing per WinRT / Metro . Bummer

EDIT 2 : I seguenti sono i metadati trovati usando "Vai alla definizione" in 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 : questo problema è stato sollevato nei forum UserVoice di Visual Studio. L'ultimo aggiornamento afferma:

INIZIATO · Visual Studio Team ADMIN Il team di Visual Studio (Product Team, Microsoft Visual Studio) ha risposto · 25 aprile 2016 Grazie per il feedback. Abbiamo iniziato a lavorare su questo.

Pratap Lakshman Visual Studio

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


4
Windows Phone è ora supportato anche, con Visual Studio 2012 Update 2 (attualmente, CTP 4)
Pedro Lamas

8
Ho l'aggiornamento 1 ma DataTestMethod e DataRow non sono riconosciuti, in quale libreria sono presenti questi attributi?
DevDave,

3
Esiste una fonte ufficiale su DataTestMethod? In quale spazio dei nomi si trova, in quale assembly?
Igor Lankin,

2
Ho scoperto che UnitTestFramework.dll è stato installato sul mio computer e dopo averlo fatto riferimento manualmente sono stato in grado di scrivere un metodo utilizzando l'attributo [DataTestMethod] con righe di dati, ma non riesco a trovare Test Explorer in Visual Studio 2012.3 per trovare il metodo.
Josh DeLong,

5
Sono andato al percorso del file "C: \ Programmi (x86) \ Microsoft SDKs \ Windows \ v8.0 \ ExtensionSDKs \ MSTestFramework \ 11.0 \ References \ CommonConfiguration \ neutral \ Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll" sul mio computer e il file era lì. Quindi l'ho fatto riferimento nel mio progetto base di unit test. L'apertura della dll in JustDecompile mostra che la libreria ha solo riferimenti a mscorlib, System e System.Core. Non è un progetto di Windows Store.
Josh DeLong,

34

Questa funzione è in pre-release e funziona con Visual Studio 2015.

Per esempio:

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

Questa è la risposta corretta Si noti che non è necessario dire [DataTestMethod] per utilizzare [DataRow] ( stackoverflow.com/a/59162403/2540235 )
mattavatar

11

Non esattamente lo stesso degli attributi di NUnit Value(o TestCase), ma MSTest ha l' DataSourceattributo, che ti consente di fare una cosa simile.

Puoi collegarlo al database o al file XML: non è così semplice come la funzionalità di NUnit, ma fa il lavoro.



6

È molto semplice da implementare: dovresti usare TestContextproprietà e TestPropertyAttribute.

Esempio

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

MODIFICARE:

Ho preparato alcuni metodi di estensione per semplificare l'accesso alla TestContextproprietà e agire come se avessimo diversi casi di test. Vedi esempio con l'elaborazione di semplici proprietà di test qui:

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

ed esempio con la creazione di oggetti di test complessi:

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

Dai un'occhiata ai metodi di estensione e al set di campioni per maggiori dettagli.


2
Questo approccio funziona ma non crea casi di test individuali per ogni set di parametri.
usr4896260,

Puoi usare qualcosa di più complesso come valore TestProperty (es. "0-100"), analizzarlo e gestirlo nel corpo del test.
Andrey Burykin,

4

Esiste, ovviamente, un altro modo per farlo che non è stato discusso in questo thread, vale a dire mediante ereditarietà della classe contenente il TestMethod. Nel seguente esempio, è stato definito un solo TestMethod ma sono stati creati due casi di test.

In Visual Studio 2012, crea due test in 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) { }
    }


3

Non riuscivo a far funzionare The DataRowAttributein Visual Studio 2015, e questo è quello con cui sono finito:

[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 vera soluzione qui è semplicemente usare NUnit (a meno che tu non sia bloccato in MSTest come me in questo particolare caso).


3
dovresti dividere ogni chiamata di prova in una prova separata per farti risparmiare tempo quando una di esse si interromperà. (che tutti sappiamo succederà)
argento

Sì, naturalmente. In pratica è così che si farebbe. In questo caso lo stavo solo illustrando per semplicità
Brandon,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.