Kontrolní výrazy MSTest

Assert Pomocí tříd Microsoft.VisualStudio.TestTools.UnitTesting oboru názvů ověřte konkrétní funkce. Testovací metoda provádí cvičení kódu v aplikaci, ale hlásí správnost pouze v případech, kdy zahrnete Assert příkazy.

Přehled

MSTest poskytuje tři třídy asertivních výrazů:

Class Účel
Assert Univerzální tvrzení pro hodnoty, typy a výjimky.
StringAssert Řetězci specifická tvrzení pro vzory, podřetězce a porovnání.
CollectionAssert Aserce pro porovnávání a ověřování kolekcí

Důležitý

Pro nový kód vždy používejte Assert třídu. Třídy StringAssert a CollectionAssert budou pravděpodobně v některé z budoucích verzí označeny jako zastaralé. Zachovávají se především kvůli zpětné kompatibilitě, ale nedoporučují se, protože rozdělení tvrzení do tří typů zhoršuje jejich dohledatelnost.

Všechny metody kontrolního výrazu přijímají volitelný parametr zprávy, který se zobrazí, když kontrolní výraz selže, a pomáhá identifikovat příčinu:

Assert.AreEqual(expected, actual, "Values should match after processing");

Třída Assert

Pomocí třídy Assert ověřte, že se kód v testu chová podle očekávání.

Poznámka:

Počínaje verzí MSTest 4.0 všechna Assert rozhraní API zachytí výraz argumentu a zahrnou ho do zpráv o selhání. Tato podpora poskytuje bohatší diagnostiku bez ručního message parametru.

Běžné asertní metody

[TestMethod]
public async Task AssertExamples()
{
    // Equality
    Assert.AreEqual(5, calculator.Add(2, 3));
    Assert.AreNotEqual(0, result);

    // Reference equality
    Assert.AreSame(expected, actual);
    Assert.AreNotSame(obj1, obj2);

    // Boolean conditions
    Assert.IsTrue(result > 0);
    Assert.IsFalse(string.IsNullOrEmpty(name));

    // Null checks
    Assert.IsNull(optionalValue);
    Assert.IsNotNull(requiredValue);

    // Type checks
    Assert.IsInstanceOfType<IDisposable>(obj);
    Assert.IsNotInstanceOfType<string>(obj);

    // Exception testing (MSTest v3.8+)
    Assert.ThrowsExactly<ArgumentNullException>(() => service.Process(null!));
    await Assert.ThrowsExactlyAsync<InvalidOperationException>(
        async () => await service.ProcessAsync());
}

Metoda Assert.That

Počínaje verzí MSTest 4.0 Assert.That vyhodnocuje jakýkoli logický výraz a vytvoří jasnou zprávu o selhání. Pro podrobnější diagnostiku Assert.That používá [CallerArgumentExpression] k automatickému zachycení textu výrazu.

Assert.That(order.Total > 0);

Dostupná rozhraní API

Poznámka:

Počínaje verzí MSTest 3.8 zahrnují kontrolní výrazy pro kolekce Assert.Contains, Assert.DoesNotContain, Assert.HasCount, Assert.IsEmpty, Assert.IsNotEmpty a Assert.ContainsSingle.

Počínaje verzí MSTest 3.10 zahrnují porovnávací aserce Assert.IsInRange, Assert.IsGreaterThan, Assert.IsGreaterThanOrEqualTo, Assert.IsLessThan, Assert.IsLessThanOrEqualTo, Assert.IsPositive a Assert.IsNegative.

Od verze MSTest 3.10 zahrnují tvrzení pro porovnávání řetězců Assert.StartsWith, Assert.EndsWith, Assert.MatchesRegex, Assert.DoesNotStartWith, Assert.DoesNotEndWith a Assert.DoesNotMatchRegex.

Počínaje verzí MSTest 4.1, Assert.IsExactInstanceOfType a Assert.IsNotExactInstanceOfType vyžadují přesnou shodu typu. Na rozdíl od Assert.IsInstanceOfType tyto metody neodpovídají odvozeným typům.

Nové aserce pro kolekce a ekvivalenci v MSTest 4.3

Poznámka:

Následující metody asercí byly zavedeny v MSTest 4.3.0.

  • Assert.AreSequenceEqual / Assert.AreNotSequenceEqual — porovnání sekvencí podle prvků. Předejte SequenceOrder.InAnyOrder, chcete-li ignorovat pořadí prvků.
  • Assert.AreEquivalent / Assert.AreNotEquivalent — hluboké strukturální porovnání dvou objektů nebo kolekcí.
  • Assert.ContainsAll / Assert.DoesNotContainAll — ověřte, že kolekce obsahuje (nebo neobsahuje) každý očekávaný prvek.
  • Assert.AreAllNotNull — ověří, že každý prvek kolekce není null.
  • Assert.AreAllDistinct — tvrdí, že všechny prvky kolekce jsou odlišné.
  • Assert.AreAllOfType — tvrdí, že každý prvek kolekce je očekávaného typu.

Při porovnávání kolekcí upřednostněte tyto metody před Assert.AreEqual, který porovnává odkazy namísto prvků.

MSTest 4.3 také přidává:

  • Assert.AddValueFormatter přizpůsobit způsob, jakým se hodnoty zobrazují ve zprávách o selhání asercí.
  • Přetížení Span<T> a Memory<T> pro Assert.HasCount.
  • Strukturované zprávy o selhání aserce pro Assert.IsTrue, Assert.IsFalse, Assert.IsNull a Assert.IsNotNull, které zahrnují vyhodnocený výraz.
  • Přetížení metod se zprávami ve formě interpolovaných řetězců pro asynchronní metody Assert.ThrowsAsync/Assert.ThrowsExactlyAsync a odmítnutí delegátů vracejících ValueTask<TResult>, na které by se jinak nečekalo.

Měkká tvrzení s Assert.Scope()

Důležitý

Assert.Scope() je experimentální rozhraní API. Při jeho použití se vygeneruje diagnostická zpráva MSTESTEXP, kterou potlačíte (například pomocí #pragma warning disable MSTESTEXP nebo v souboru .editorconfig vašeho projektu), čímž berete na vědomí, že tvar a chování rozhraní API se mohou v budoucích verzích změnit.

Ve výchozím nastavení každý asert vyvolá výjimku AssertFailedException, jakmile selže, čímž se test okamžitě ukončí. Assert.Scope() zavádí měkké kontrolní výrazy: zatímco obor je aktivní, místo vyvolání se shromažďují selhání kontrolních výrazů, takže provádění pokračuje a vy můžete vidět všechna selhání v oboru najednou. Po ukončení rozsahu se shromážděná selhání nahlásí společně:

[TestMethod]
public void ValidatePerson()
{
    using (Assert.Scope())
    {
        Assert.AreEqual("Jane", person.FirstName); // failure collected, execution continues
        Assert.AreEqual("Doe", person.LastName);   // failure collected, execution continues
        Assert.IsTrue(person.IsActive);            // failure collected, execution continues
    }
    // On Dispose, all collected failures are reported together.
}

Při zrušení rozsahu:

  • Pokud se shromáždí právě jedna chyba, vyvolá se původní AssertFailedException chyba.
  • Pokud bylo zachyceno více výjimek, vyvolá se jediný AssertFailedException, který je všechny zapouzdřuje do AggregateException.

Postconditions se nevynucují v rámci oboru.

Protože neúspěšná aserce už v rámci bloku nevyvolá výjimku, kód, který se spustí po ní, se nemůže spoléhat na to, že aserce proběhla úspěšně. To platí pro každou postpodmínku, včetně nulovatelnosti a zúžení typu:

using (Assert.Scope())
{
    Assert.IsNotNull(item);
    // 'item' might still be null here: the failure was collected, not thrown.
    Assert.AreEqual("expected", item.Value);
    // 'item.Value' might not equal "expected" either.
}

Pokud by selhané tvrzení vedlo na některém pozdějším řádku v rámci daného rozsahu k NullReferenceException (nebo jakékoli jiné výjimce), je tato sekundární výjimka příznakem již zaznamenaného selhání, nikoli samostatné chyby. Původní chyba kontrolního výrazu je stále hlášena, když je obor uvolněn.

Kontrolní výrazy vracející hodnotu se vrátí null/default při selhání v rámci oboru.

Některé aserce po úspěšném vyhodnocení vracejí hodnotu — například Throws a ThrowsExactly vracejí zachycenou výjimku a ContainsSingle vrací odpovídající prvek. Pokud některý z těchto kontrolních výrazů selže uvnitř oboru, je chyba shromážděna a metoda vrátí null/default místo vyvolání:

using (Assert.Scope())
{
    // No exception is thrown by the lambda, so the assertion fails. The failure is
    // collected and 'ex' is null. Accessing 'ex' below throws NullReferenceException.
    InvalidOperationException ex = Assert.Throws<InvalidOperationException>(() => { });
    _ = ex.Message; // NullReferenceException—don't use the return value in a scope
}

Nespoléhejte na hodnotu vrácenou měkkým ověřením v rámci bloku. Pokud potřebujete vrácenou hodnotu (například zachycenou výjimku), zavolejte aserci mimo blok nebo test přepracujte tak, aby nic nezáviselo na návratové hodnotě, dokud není blok ukončen.

Assert.Fail a Assert.Inconclusive vždy vyvolají

Fail a Inconclusive nikdy nejsou měkké. Vždy hází okamžitě, i uvnitř oboru, protože vyjadřují nepodmíněný výsledek testu. Použijte jeden z nich, pokud je podmínka kritická a zbytek testu nemůže bez ní smysluplně pokračovat.

Vnořené rozsahy nejsou podporovány.

Volání Assert.Scope() nelze vnořovat. Najednou může být aktivní pouze jeden rozsah kontrolního výrazu.

Třída StringAssert

StringAssert Pomocí třídy můžete porovnávat a zkoumat řetězce.

Warning

Třída StringAssert bude pravděpodobně v budoucí verzi zastaralá. Udržuje se jenom kvůli zpětné kompatibilitě a nedoporučuje se pro nový kód. Všechny StringAssert metody mají ve třídě ekvivalenty Assert , což nabízí lepší zjistitelnost. Informace o migraci stávajících použití najdete v analyzátoru MSTEST0046.

Dostupná rozhraní API jsou:

Třída CollectionAssert

CollectionAssert Třída slouží k porovnání kolekcí objektů nebo k ověření stavu kolekce.

Warning

Třída CollectionAssert bude pravděpodobně v budoucí verzi zastaralá. Udržuje se primárně kvůli zpětné kompatibilitě a nedoporučuje se pro nový kód. Pokud existuje Assert ekvivalentní metoda (například Assert.Contains, Assert.DoesNotContainnebo Assert.HasCount), použijte Assert pro lepší zjistitelnost.

Dostupná rozhraní API jsou:

Vytvořte vlastní tvrzení pomocí Assert.That

Předdefinované metody asercí nepokrývají všechny scénáře. Chcete-li rozšířit kontrolní infrastrukturu vlastními kontrolami, MSTest zveřejňuje Assert.That vlastnost singleton jako háček rozšiřitelnosti. Vlastní kontrolní výrazy přidáte jako metody rozšíření jazyka C# pro Assert typ instance a volající je vyvolá pomocí známé Assert.That.MyAssertion(...) syntaxe.

Pro snazší dohledatelnost uspořádejte tvrzení v rámci projektu do vyhrazené statické třídy. Vlastní aserce zpřístupněné přes Assert.That se v IntelliSense zobrazují vedle vestavěných metod, takže si uživatelé nemusí pamatovat samostatný pomocný typ.

Vytvořit vlastní tvrzení

Přidejte metodu rozšíření pro typ Assert, která vyvolá AssertFailedException, pokud podmínka není splněna:

using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

public static class CustomAssertExtensions
{
    public static void IsPrime(this Assert assert, int value)
    {
        if (value < 2 || Enumerable.Range(2, (int)Math.Sqrt(value) - 1).Any(i => value % i == 0))
        {
            throw new AssertFailedException($"Assert.That.IsPrime failed. Value <{value}> is not a prime number.");
        }
    }
}

Použijte vlastní tvrzení

Po importování oboru názvů, který obsahuje vaše rozšiřující metody, zavolejte vlastní aserci pomocí Assert.That:

[TestMethod]
public void Compute_ReturnsPrime()
{
    int result = _calculator.NextPrime(10);
    Assert.That.IsPrime(result);
}

Hooky rozšíření na StringAssert a CollectionAssert

Vlastnosti StringAssert.That a CollectionAssert.That zpřístupňují stejný jednotonový vzor pro zpětnou kompatibilitu. Pro nové vlastní aserce vždy cílte na Assert.That. Jinak vaše pomocné třídy zdědí stejné problémy s dohledatelností jako starší třídy a bude je potřeba migrovat, pokud budou StringAssert a CollectionAssert zastaralé.

Assert.That vlastnost versus Assert.That(...) metoda

Poznámka:

Nezaměňujte vlastnost Assert.That singleton používanou jako bod rozšíření s Assert.That(() => condition)metodou přidanou v MSTest 3.8. Druhý z nich přijímá logický výraz a na základě analýzy stromu výrazů vytváří podrobná chybová hlášení (například Assert.That(() => order.Total > 0)). Tato dvě rozhraní API sdílejí název, ale slouží k různým účelům.

Osvědčené postupy

  • Používejte konkrétní kontrolní výrazy: Upřednostněte AreEqual před IsTrue(a == b) kvůli lepším zprávám o selhání.

  • Zahrnout popisné zprávy: Pomáhá rychle identifikovat chyby pomocí jasných kontrolních zpráv.

  • Otestujte jednu věc najednou: Každá testovací metoda by měla ověřit jedno chování.

  • Použijte Throws/ThrowsExactly pro výjimky: V MSTest v3.8+ dávejte přednost Assert.Throws, Assert.ThrowsExactly a jejich asynchronním protějškům (ThrowsAsync, ThrowsExactlyAsync) před atributem ExpectedException.

  • Upřednostněte Assert před StringAssert/CollectionAssert: Pro snazší dohledatelnost a konzistentnost použijte třídu Assert. Třídy StringAssert a CollectionAssert budou pravděpodobně v některé z budoucích verzí označeny jako zastaralé.

  • Rozšiřte Assert.That pro vlastní tvrzení: Kvůli konzistentní a snadné dohledatelnosti přidejte vlastní tvrzení jako metody rozšíření pro Assert a volejte je prostřednictvím Assert.That. Necílit StringAssert.That ani CollectionAssert.That v novém kódu.

Následující analyzátory pomáhají zajistit správné použití asercí:

  • MSTEST0006 – Vyhněte se ExpectedException atributu, místo toho používejte Assert.Throws metody.
  • MSTEST0017 – argumenty aserce by měly být předány ve správném pořadí.
  • MSTEST0023 – Negujte logické kontrolní výrazy.
  • MSTEST0025 – upřednostňujte Assert.Fail před podmínkami vždy nepravdivými.
  • MSTEST0026 – argumenty aserce by se měly vyhnout podmíněnému přístupu.
  • MSTEST0032 – Zkontrolujte podmínky kontrolního výrazu always-true.
  • MSTEST0037 – použijte správné metody assert.
  • MSTEST0038 – vyhněte se Assert.AreSame typům hodnot.
  • MSTEST0039 – používejte novější Assert.Throws metody.
  • MSTEST0040 – Vyhněte se použití asercí v kontextu asynchronního voidu.
  • MSTEST0046 – používejte Assert místo StringAssert.
  • - Assert.Throws MSTEST0051 by měl obsahovat jeden příkaz.
  • MSTEST0053 – Vyhněte se Assert parametrům formátu.
  • MSTEST0058 – Vyhněte se asercím v blocích catch.

Viz také