Testgenerering

I traditionell enhetstestning består ett test av flera saker:

Följande är ett exempel på en teststruktur:

[Test]
void MyTest() {
    // data
    ArrayList a = new ArrayList();

    // method sequence
    a.Add(5);

    // assertions
    Assert.IsTrue(a.Count==1);
    Assert.AreEqual(a[0], 5);
}

IntelliTest kan ofta automatiskt fastställa relevanta argumentvärden för mer allmänna parameteriserade enhetstester, vilket ger sekvensen med metodanrop och -försäkran.

Testgeneratorer

IntelliTest genererar testfall genom att välja en sekvens med metoder för implementeringen under test som ska köras och sedan generera indata för metoderna vid kontroll av försäkran över härledda data.

Ett parameteriserat enhetstest anger direkt en sekvens med metodanrop i dess brödtext.

När IntelliTest behöver konstruera objekt läggs anrop till konstruktorer och fabriksmetoder automatiskt till i sekvensen efter behov.

Parametriserad enhetstestning

Parametriserade enhetstester (PUT) är tester som tar parametrar. Till skillnad från traditionella enhetstester, som vanligtvis är stängda metoder, tar PUT alla uppsättningar parametrar. Är det så enkelt? Ja – därifrån försöker IntelliTest generera den (minimala) uppsättningen indata som helt täcker den kod som kan nås från testet.

PUT definieras med det anpassade attributet PexMethod på ett liknande sätt som MSTest (eller NUnit, xUnit). PUT är instansmetoder som är logiskt grupperade i klasser som är märkta med PexClass. I följande exempel visas en enkel PUT som lagras i klassen MyPexTest :

[PexMethod]
void ReplaceFirstChar(string target, char c) {

    string result = StringHelper.ReplaceFirstChar(target, c);

    Assert.AreEqual(result[0], c);
}

där ReplaceFirstChar är en metod som ersätter det första tecknet i en sträng:

class StringHelper {
    static string ReplaceFirstChar(string target, char c) {
        if (target == null) throw new ArgumentNullException();
        if (target.Length == 0) throw new ArgumentOutOfRangeException();
        return c + target.Substring(1);
    }
}

Från det här testet kan IntelliTest automatiskt generera indata för en PUT vilket täcker många exekveringsvägar för den testade koden. Varje indata som täcker en annan exekveringssökväg blir "serieförvandlad" som ett enhetstest:

[TestMethod, ExpectedException(typeof(ArgumentNullException))]
void ReplaceFirstChar0() {
    this.ReplaceFirstChar(null, 0);
}
...
[TestMethod]
void ReplaceFirstChar10() {
    this.ReplaceFirstChar("a", 'c');
}

Allmän parametriserad enhetstestning

Parameteriserade enhetstester kan vara generiska metoder. I det här fallet måste användaren ange de typer som används för att instansiera metoden med hjälp av PexGenericArguments.

[PexClass]
public partial class ListTest {
    [PexMethod]
    [PexGenericArguments(typeof(int))]
    [PexGenericArguments(typeof(object))]
    public void AddItem<T>(List<T> list, T value)
    { ... }
}

Tillåta undantag

IntelliTest tillhandahåller många valideringsattribut som hjälper till att sortera undantag i förväntade undantag och oväntade undantag.

Förväntade undantag genererar negativa testfall med lämplig kommentar, till exempel ExpectedException(typeof(xxx)), medan oväntade undantag genererar misslyckade testfall.

[PexMethod, PexAllowedException(typeof(ArgumentNullException))]
void SomeTest() {...}

Validatorerna är:

Testning av interna typer

IntelliTest kan "testa" interna typer, så länge det kan se dem. För att IntelliTest ska kunna se typerna läggs följande attribut till i produkten eller testprojektet av Visual Studio IntelliTest-guiderna:

[assembly: InternalsVisibleTo("Microsoft.Pex, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]

Antaganden och intyg

Användare kan använda antaganden och intyg för att uttrycka förhandsvillkor (antaganden) och postkonditioner (intyg) om sina tester. När IntelliTest genererar en uppsättning parametervärden och "utforskar" koden kan det strida mot ett antagande om testet. När det händer genererar den inte ett test för den sökvägen utan ignorerar den tyst.

Påståenden är ett välkänt begrepp i vanliga enhetstestramverk, så IntelliTest "förstår" redan de inbyggda Assert-klasserna som tillhandahålls av varje testramverk som stöds. De flesta ramverk tillhandahåller dock inte en Anta-klass . I så fall tillhandahåller IntelliTest klassen PexAssume . Om du inte vill använda ett befintligt testramverk har IntelliTest även klassen PexAssert .

[PexMethod]
public void Test1(object o) {
    // precondition: o should not be null
    PexAssume.IsNotNull(o);

    ...
}

I synnerhet kan antagandet om icke-nullness kodas som ett anpassat attribut:

[PexMethod]
public void Test2([PexAssumeNotNull] object o)
// precondition: o should not be null
{
   ...
}

Förutsättning

En förutsättning för en metod uttrycker villkoren för att metoden ska lyckas.

Vanligtvis framtvingas förhandsvillkoret genom att kontrollera parametrarna och objekttillståndet och generera ett ArgumentException eller InvalidOperationException om det överträds.

I IntelliTest uttrycks en förutsättning för ett parameteriserat enhetstest med PexAssume.

Postvillkor

En postkondition av en metod uttrycker de villkor som bör gälla under och efter körningen av metoden, förutsatt att dess förhandsvillkor ursprungligen var giltiga.

Vanligtvis säkerställs postkonditionen av anrop till Assert-metoder.

Med IntelliTest uttrycks en postkondition av ett parameteriserat enhetstest med PexAssert.

Tester som misslyckades

När misslyckas ett genererat testfall?

  1. Om den inte avslutas inom de konfigurerade sökvägsgränsen betraktas den som ett fel om inte alternativet TestExcludePathBoundsExceeded har angetts

  2. Om testet genererar en PexAssumeFailedException lyckas det. Den filtreras dock vanligtvis bort om inte TestEmissionFilter är inställt på Alla

  3. Om testet bryter mot ett intyg; till exempel genom att utlösa ett undantag för kontrollöverträdelse i ett enhetstestningsramverk misslyckas det

Om inget av ovanstående genererar ett beslut lyckas ett test om och endast om det inte utlöser ett undantag. Överträdelser av försäkran behandlas på samma sätt som undantag.

Konfigurera och avinstallation

Som en del av integreringen med testramverk har IntelliTest stöd för att identifiera och köra installationsmetoder och riva ned metoder.

Exempel

using Microsoft.Pex.Framework;
using NUnit.Framework;

namespace MyTests
{
    [PexClass]
    [TestFixture]
    public partial class MyTestClass
    {
        [SetUp]
        public void Init()
        {
            // monitored
        }

        [PexMethod]
        public void MyTest(int i)
        {
        }

        [TearDown]
        public void Dispose()
        {
            // monitored
        }
    }
}

Ytterligare läsning

Fick du feedback?

Publicera dina idéer och funktionsförfrågningar i Utvecklarcommunityn.