Dela via


Skapa ett datadrivet enhetstest

Du kan använda Microsofts enhetstestramverk (MSTest) för hanterad kod för att konfigurera en enhetstestmetod för att hämta värden från en datakälla. Metoden körs successivt för varje rad i datakällan, vilket gör det enkelt att testa en mängd olika indata med hjälp av en enda metod.

Ett datadrivet enhetstest kan använda någon av följande slag:

  • infogade data med hjälp av attributet DataRow
  • medlemsdata med attributet DynamicData
  • från någon välkänd källprovider med hjälp av attributet DataSource

Metoden som testas

Anta till exempel att du har:

  1. En lösning som kallas MyBank som accepterar och bearbetar transaktioner för olika typer av konton.

  2. Ett projekt i MyBank med namnet BankDb som hanterar transaktionerna för konton.

  3. En klass med namnet Maths i projektet BankDb som utför de matematiska funktionerna för att säkerställa att alla transaktioner är fördelaktiga för banken.

  4. Ett enhetstestprojekt med namnet BankDbTests för att testa beteendet för den BankDb komponenten.

  5. En enhetstestklass med namnet MathsTests för att verifiera beteendet för klassen Maths.

Vi testar en metod i Maths som lägger till två heltal med hjälp av en loop:

public int AddIntegers(int first, int second)
{
    int sum = first;
    for (int i = 0; i < second; i++)
    {
        sum += 1;
    }

    return sum;
}

Testmetod

Inbäddat datadrivet test

För inlinjetester använder MSTest DataRow för att ange värden som används av det datadrivna testet. Testet i det här exemplet körs successivt för varje datarad.

[TestMethod]
[DataRow(1, 1, 2)]
[DataRow(2, 2, 4)]
[DataRow(3, 3, 6)]
[DataRow(0, 0, 1)] // The test run with this row fails
public void AddIntegers_FromDataRowTest(int x, int y, int expected)
{
    var target = new Maths();
    int actual = target.AddIntegers(x, y);
    Assert.AreEqual(expected, actual,
        "x:<{0}> y:<{1}>",
        new object[] {x, y});
}

Datadrivet medlemstest

MSTest använder DynamicData attribut för att ange namn, typ (egenskap, standard eller metod) och definiera typ (som standard aktuell typ används) för medlemmen som tillhandahåller de data som används av det datadrivna testet.

public static IEnumerable<object[]> AdditionData
{
    get
    {
        return new[]
        { 
            new object[] { 1, 1, 2 },
            new object[] { 2, 2, 4 },
            new object[] { 3, 3, 6 },
            new object[] { 0, 0, 1 }, // The test run with this row fails
        };
    }
}

[TestMethod]
[DynamicData(nameof(AdditionData))]
public void AddIntegers_FromDynamicDataTest(int x, int y, int expected)
{
    var target = new Maths();
    int actual = target.AddIntegers(x, y);
    Assert.AreEqual(expected, actual,
        "x:<{0}> y:<{1}>",
        new object[] {x, y});
}

Det går också att åsidosätta det standardgenererade visningsnamnet med hjälp av egenskapen DynamicDataDisplayName för attributet DynamicData. Visningsnamnets metodsignatur måste vara public static string och acceptera två parametrar, den första av typen MethodInfo och den andra av typen object[].

public static string GetCustomDynamicDataDisplayName(MethodInfo methodInfo, object[] data)
{
    return string.Format("DynamicDataTestMethod {0} with {1} parameters", methodInfo.Name, data.Length);
}

[DynamicData(nameof(AdditionData), DynamicDataDisplayName = nameof(GetCustomDynamicDataDisplayName))]

Datadrivet test för källprovider

När du skapar ett test av en datakälladriven enhet ingår följande steg:

  1. Skapa en datakälla som innehåller de värden som du använder i testmetoden. Datakällan kan vara vilken typ som helst som är registrerad på den dator som kör testet.

  2. Lägg till en offentlig TestContext egenskap av typen TestContext till testklassen.

  3. Skapa en enhetstestmetod

  4. Lägg till ett DataSourceAttribute attribut i det.

  5. Använd egenskapen DataRow indexerare för att hämta de värden som du använder i ett test.

Skapa en datakälla

Om du vill testa metoden AddIntegers skapar du en datakälla som anger ett värdeintervall för parametrarna och summan som du förväntar dig ska returneras. I det här exemplet skapar vi en Sql Compact-databas med namnet MathsData och en tabell med namnet AddIntegersData som innehåller följande kolumnnamn och värden

FirstNumber SecondNumber Summa
0 1 1
1 1 2
2 -3 -1

Lägga till en TestContext i testklassen

Enhetstestramverket skapar ett TestContext objekt för att lagra datakällans information för ett datadrivet test. Ramverket anger sedan det här objektet som värdet för den TestContext egenskap som du skapar.

public TestContext TestContext { get; set; }

I din testmetod får du åtkomst till data genom egenskapen hos DataRow-indexeraren för TestContext.

Not

.NET Core stöder inte attributet DataSource. Om du försöker komma åt testdata på det här sättet i ett .NET Core-, UWP- eller WinUI-enhetstestprojekt visas ett fel som liknar "TestContext" inte innehåller någon definition för "DataRow" och ingen tillgänglig tilläggsmetod "DataRow" som accepterar ett första argument av typen "TestContext" kunde hittas (saknar du ett användningsdirektiv eller en sammansättningsreferens?)".

Skriva testmetoden

Testmetoden för AddIntegers är ganska enkel. För varje rad i datakällan anropar du AddIntegers med FirstNumber och SecondNumber kolumnvärden som parametrar och verifierar returvärdet mot Summa kolumnvärde:

[TestMethod]
[DataSource(@"Provider=Microsoft.SqlServerCe.Client.4.0; Data Source=C:\Data\MathsData.sdf;", "Numbers")]
public void AddIntegers_FromDataSourceTest()
{
    var target = new Maths();

    // Access the data
    int x = Convert.ToInt32(TestContext.DataRow["FirstNumber"]);
    int y = Convert.ToInt32(TestContext.DataRow["SecondNumber"]);
    int expected = Convert.ToInt32(TestContext.DataRow["Sum"]);
    int actual = target.AddIntegers(x, y);
    Assert.AreEqual(expected, actual,
        "x:<{0}> y:<{1}>",
        new object[] {x, y});
}

Ange DataSourceAttribute

Attributet DataSource anger anslutningssträngen för datakällan och namnet på den tabell som du använder i testmetoden. Den exakta informationen i anslutningssträngen skiljer sig åt beroende på vilken typ av datakälla du använder. I det här exemplet använde vi en SqlServerCe-databas.

[DataSource(@"Provider=Microsoft.SqlServerCe.Client.4.0;Data Source=C:\Data\MathsData.sdf", "AddIntegersData")]

Försiktighet

Anslutningssträngen kan innehålla känsliga data (till exempel ett lösenord). Anslutningssträngen lagras i oformaterad text i källkoden och i den kompilerade sammansättningen. Begränsa åtkomsten till källkoden och sammansättningen för att skydda den här känsliga informationen.

Attributet DataSource har tre konstruktorer.

[DataSource(dataSourceSettingName)]

En konstruktor med en parameter använder anslutningsinformation som lagras i app.config-filen för lösningen. dataSourceSettingsName är namnet på XML-elementet i konfigurationsfilen som anger anslutningsinformationen.

Med hjälp av en app.config-fil kan du ändra datakällans plats utan att göra ändringar i själva enhetstestet. Information om hur du skapar och använder en app.config-fil finns i Guide: Använda en konfigurationsfil för att definiera en datakälla

[DataSource(connectionString, tableName)]

Den DataSource konstruktorn med två parametrar anger anslutningssträngen för datakällan och namnet på tabellen som innehåller data för testmetoden.

Anslutningssträngarna beror på typen av datakälla, men den bör innehålla ett providerelement som anger dataproviderns invarianta namn.

[DataSource(
    dataProvider,
    connectionString,
    tableName,
    dataAccessMethod
    )]

Använd TestContext.DataRow för att komma åt data

Om du vill komma åt data i tabellen AddIntegersData använder du TestContext.DataRow indexeraren. DataRow är ett DataRow objekt, så hämta kolumnvärden efter index- eller kolumnnamn. Eftersom värdena returneras som objekt konverterar du dem till rätt typ:

int x = Convert.ToInt32(TestContext.DataRow["FirstNumber"]);

Kör testet och visa resultat

När du har skrivit en testmetod skapar du testprojektet. Testmetoden visas i Test Explorer i gruppen Tester som inte är körda. När du kör, skriver och kör testerna igen, visar Test Explorer resultaten i grupper med Misslyckade tester, Godkända testeroch Tester som inte har körts. Du kan välja Kör alla för att köra alla dina tester eller välja Kör för att välja en delmängd av testerna som ska köras.

Testresultatstapeln överst i Test Explorer animeras medan testet körs. I slutet av testkörningen är fältet grönt om alla tester har godkänts eller är röda om något av testerna har misslyckats. En sammanfattning av testkörningen visas i informationsfönstret längst ned i testutforskarens fönster. Välj ett test för att visa information om testet i det nedre fönstret.

Notera

Det finns ett resultat för varje rad med data och även ett sammanfattningsresultat. Om testet skickades på varje rad med data visas sammanfattningskörningen som Godkänd. Om testet misslyckades på någon datarad visas sammanfattningen av körningen som Misslyckades.

Om du körde någon av metoden AddIntegers_FromDataRowTest, AddIntegers_FromDynamicDataTest eller AddIntegers_FromDataSourceTest i vårt exempel blir resultatfältet rött och testmetoden flyttas till Misslyckade tester. Ett datadrivet test misslyckas om någon av de itererade metoderna från datakällan misslyckas. När du väljer ett misslyckat datadrivet test i Testutforskaren-fönstret visas resultaten av varje iteration som identifieras av dataradsindexet i informationsfönstret. I vårt exempel verkar det som om AddIntegers-algoritmen inte hanterar negativa värden korrekt.

När metoden under test korrigeras och testkörningen körs igen blir resultatfältet grönt och testmetoden flyttas till gruppen Godkänt test.