Jak możemy uruchomić metodę testową z wieloma parametrami w MSTest?

140

NUnit ma funkcję o nazwie Wartości, jak poniżej:

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

Oznacza to, że metoda testowa będzie działać sześć razy:

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

Używamy teraz MSTest, ale czy istnieje odpowiednik tego, abym mógł uruchomić ten sam test z wieloma parametrami?

[TestMethod]
public void Mytest()
{
    // ...
}
Światło
źródło
Możesz użyć MSTestHacks, zgodnie z opisem na stackoverflow.com/a/19536942/52277 answer.
Michael Freidgeim
Możliwy duplikat How to RowTest z MSTest?
Michael Freidgeim
@MichaelFreidgeim To pytanie ma lepsze odpowiedzi niż sugerowany cel
Rob
1
@Rob: IMHO, najbardziej odpowiednia odpowiedź -MSTestHacks - Jak RowTest z MSTest? brakuje w tym pytaniu.
Michael Freidgeim
@MichaelFreidgeim Być może, chociaż wygląda na to, że funkcjonalność istnieje od 3 i pół roku ( stackoverflow.com/questions/9021881/ ... )
Rob

Odpowiedzi:

46

Niestety nie jest obsługiwany w starszych wersjach MSTest. Najwyraźniej istnieje model rozszerzalności i można go zaimplementować samodzielnie . Inną opcją byłoby użycie testów opartych na danych .

Moja osobista opinia byłaby jednak taka, aby trzymać się NUnit ...

Począwszy od programu Visual Studio 2012, aktualizacja 1, MSTest ma podobną funkcję. Zobacz odpowiedź McAdena .

jeroenh
źródło
Używamy Selenium, które generuje kod NUnit, więc zamiast tego przełączyliśmy się na NUnit :)
The Light
4
Odkryłem, że coś podobnego jest teraz możliwe w Visual Studio 2012 Update 1, tylko do Twojej wiadomości, aby w przyszłości rozważyć każdy, kto spojrzy na tę odpowiedź.
McAden
@McAden Czy masz link z wyjaśnieniem?
jeroenh
6
Poniżej podałem odpowiedź z przykładem i linkiem do mojego wpisu na blogu. Wymienia niezbędne atrybuty, a także właściwość „DisplayName” atrybutu, który wyróżnia przypadki w Eksploratorze testów. Wspomniano o tym również w październikowym ogłoszeniu CTP (które ma teraz oficjalne wydanie) blogs.msdn.com/b/visualstudioalm/archive/2012/10/26/ ... Dodałem informacje do tego pytania SO, ponieważ spędził sporo czasu na szukaniu tego. Miejmy nadzieję, że to komuś zaoszczędzi trochę czasu.
McAden
167

EDYCJA 4 : Wygląda na to, że zostało to ukończone w MSTest V2 17 czerwca 2016 r .: https://blogs.msdn.microsoft.com/visualstudioalm/2016/06/17/taking-the-mstest-framework-forward-with-mstest- v2 /

Oryginalna odpowiedź :

Mniej więcej tydzień temu w Visual Studio 2012 Update 1 jest teraz możliwe coś podobnego:

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

EDYCJA : Wygląda na to, że jest to dostępne tylko w ramach projektu testów jednostkowych dla WinRT / Metro . Porażka

EDYCJA 2 : Poniżej przedstawiono metadane znalezione za pomocą polecenia „Przejdź do definicji” w programie 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);
    }
}

EDYCJA 3 : ten problem został poruszony na forach UserVoice programu Visual Studio. Ostatnia aktualizacja stwierdza:

ROZPOCZĘTE · Zespół Visual Studio ADMIN Zespół Visual Studio (Zespół ds. Produktu, Microsoft Visual Studio) odpowiedział · 25 kwietnia 2016 r. Dziękujemy za opinię. Zaczęliśmy nad tym pracować.

Pratap Lakshman Visual Studio

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

McAden
źródło
4
Windows Phone jest teraz obsługiwany również z Visual Studio 2012 Update 2 (obecnie CTP 4)
Pedro Lamas,
8
Mam aktualizację 1, ale DataTestMethod i DataRow nie są rozpoznawane, w której bibliotece znajdują się te atrybuty?
DevDave
3
Czy jest jakieś oficjalne źródło informacji o DataTestMethod? W jakiej przestrzeni nazw się znajduje, w którym zestawie?
Igor Lankin
2
Okazało się, że na moim komputerze zainstalowano plik UnitTestFramework.dll i po ręcznym odwołaniu się do niego udało mi się napisać metodę przy użyciu atrybutu [DataTestMethod] z wierszami danych, ale nie mogę uzyskać Eksploratora testów w programie Visual Studio 2012.3, aby znaleźć metodę.
Josh DeLong
5
Udałem się do ścieżki pliku „C: \ Program Files (x86) \ Microsoft SDKs \ Windows \ v8.0 \ ExtensionSDKs \ MSTestFramework \ 11.0 \ References \ CommonConfiguration \ neutral \ Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll” na moim komputerze i plik tam był. Więc odwołałem się do tego w moim podstawowym projekcie testu jednostkowego. Otwarcie biblioteki dll w JustDecompile pokazuje, że biblioteka ma tylko odwołania do mscorlib, System i System.Core. To nie jest projekt Sklepu Windows.
Josh DeLong,
34

Ta funkcja jest teraz w wersji wstępnej i działa z programem Visual Studio 2015.

Na przykład:

[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
źródło
To jest poprawna odpowiedź. Zauważ, że nie trzeba mówić [DataTestMethod], aby użyć [DataRow] ( stackoverflow.com/a/59162403/2540235 )
mattavatar
11

Nie dokładnie to samo, co atrybuty NUnit Value(lub TestCase), ale MSTest maDataSource atrybut, który pozwala zrobić podobną rzecz.

Możesz go podłączyć do bazy danych lub pliku XML - nie jest to tak proste jak funkcja NUnit, ale spełnia swoje zadanie.

km
źródło
6

Jest bardzo prosty w implementacji - powinieneś użyć TestContextproperty iTestPropertyAttribute .

Przykład

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

EDYTOWAĆ:

Przygotowałem kilka metod rozszerzających, aby uprościć dostęp do TestContextwłaściwości i działać tak, jakbyśmy mieli kilka przypadków testowych. Zobacz przykład przetwarzania prostych właściwości testowych tutaj:

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

i przykład tworzenia złożonych obiektów testowych:

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

Zapoznaj się z metodami rozszerzającymi i zestawem próbek, aby uzyskać więcej informacji.

Andrey Burykin
źródło
2
To podejście działa, ale nie tworzy indywidualnych przypadków testowych dla każdego zestawu parametrów.
usr4896260
Możesz użyć czegoś bardziej złożonego jako wartości TestProperty (np. „0-100”), przeanalizować ją i obsłużyć w treści testu.
Andrey Burykin
4

Istnieje oczywiście inny sposób, który nie został omówiony w tym wątku, a mianowicie dziedziczenie klasy zawierającej TestMethod. W poniższym przykładzie zdefiniowano tylko jedną metodę TestMethod, ale utworzono dwa przypadki testowe.

W programie Visual Studio 2012 tworzy dwa testy w narzędziu 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
źródło
3

Nie mogłem zmusić The DataRowAttributedo pracy w Visual Studio 2015 i oto, co otrzymałem :

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

Prawdziwym rozwiązaniem jest tutaj użycie NUnit (chyba że utkniesz w MSTest, tak jak ja w tym konkretnym przypadku).

Brandon
źródło
3
Powinieneś podzielić każde wywołanie testowe na osobny test, aby zaoszczędzić czas, gdy jedno z nich się zepsuje. (co wszyscy wiemy, że tak się stanie)
srebro
Tak oczywiście. W praktyce tak by się to działo. W tym przypadku tylko zilustrowałem to dla uproszczenia
Brandon,