Testování částí nativního kódu pomocí Průzkumníka testů

V systému Visual Studio je možné vytvořit jednotkové testy pro nespravovaný kód napsaný v jazyce C++.Nespravovaný kód se někdy označuje jako nativní kód.

Následující postup obsahuje základní informace, které umožní vytváření takových testů.Pozdější části poskytují návod, který popisuje každý krok podrobněji.

Vytvoření jednotkových testů pro knihovnu DLL s nespravovaným kódem

  1. Použijte šablonu Projekt testů nativního kódu pro vytvoření samostatného projektu systému Visual Studio pro své testy.

    Projekt obsahuje ukázkový kód testu.

  2. Zpřístupněte knihovnu DLL pro projekt testů:

    • #include soubor .h, který obsahuje deklarace externě přístupných funkcí knihovny DLL.

      Soubor .h by měl obsahovat deklarace funkcí označených _declspec(dllimport).Tyto metody je také možné exportovat pomocí souboru DEF.Další informace naleznete v tématu Import a export.

      Jednotkové testy mohou přistupovat pouze k funkcím, které jsou exportovány z testované DLL knihovny.

    • Přidejte projekt knihovny DLL do Odkazů testovacího projektu:

      Ve Vlastnostech zkušebního projektu, rozbalte položku Společná nastavení, Rámec a odkazy a zvolte Přidat odkaz.

  3. V testu projektu vytvořit test třídy a zkušební metody pomocí makra TEST a Assert třídy následujícím způsobem:

    #include "stdafx.h"
    #include <CppUnitTest.h>
    #include "..\MyProjectUnderTest\MyCodeUnderTest.h"
    using namespace Microsoft::VisualStudio::CppUnitTestFramework;
    TEST_CLASS(TestClassName)
    {
    public:
      TEST_METHOD(TestMethodName)
      {
        // Run a function under test here.
        Assert::AreEqual(expectedValue, actualValue, L"message", LINE_INFO());
      }
    }
    
    • Assert obsahuje několik statických funkcí, které lze použít k ověření výsledků testu.

    • Parametr LINE_INFO() je volitelný.Tento parametr umožňuje testovacímu prostředí nalézt umístění chyby v případech, kdy není dostupný žádný soubor PDB.

    • Je také možné napsat metody pro nastavení a vyčištění testu.Další informace naleznete otevřením definice makra TEST_METHOD a přečtením komentářů v CppUnitTest.h

    • Třídy testů nemohou být vnořené.

  4. Testy se spouští pomocí Průzkumníka testů:

    1. V nabídce Zobrazit zvolte položku Ostatní okna, Průzkumník testů.

    2. Sestavte řešení v aplikaci Visual Studio.

    3. V Průzkumníku testů zvolte položku Spustit všechny.

    4. Podrobnější prozkoumání jakéhokoli testu v Průzkumníku testů:

      1. Vyberte název testu pro zobrazení dalších podrobností, například zpráv selhání a výpisů zásobníku.

      2. Otevřete název testu (například dvojitým kliknutím) pro zobrazení místa selhání nebo kódu testu.

      3. V místní nabídce testu zvolte Ladit vybrané testy pro spuštění testu v ladicím programu.

Návod: Vývoj nespravované knihovny DLL v Průzkumníku testů

Tento návod je možné si přizpůsobit pro vývoj vlastní knihovny DLL.Hlavní kroky jsou následující:

  1. Vytvoření projektu testů nativního kódu.Testy jsou vytvořeny v samostatném projektu ve vyvíjené knihovně DLL.

  2. Vytvoření projektu knihovny DLL.Tento návod ukazuje, jak vytvořit novou knihovnu DLL, ale postup pro testování existující knihovny DLL je obdobný.

  3. Zpřístupnění funkcí knihovny DLL pro testy.

  4. Postupné rozšiřování testů.Doporučujeme cyklus "červená-zelená-refaktorovat", ve kterém je vývoj kódu řízený testy.

  5. Ladění testů, které skončily neúspěšně.Testy je možné spustit v režimu ladění.

  6. Refaktorování při zachování testů beze změn.Refaktorování znamená zlepšení struktury kódu bez změny jeho vnějšího chování.Je možné ho provádět pro zlepšení výkonnosti, rozšiřitelnosti nebo čitelnosti kódu.Protože je záměrem ponechat chování nezměněné, testy by se při refaktorování kódu taktéž neměly měnit.Testy pomáhají zajistit, že při refaktorování nevznikly v kódu žádné chyby.Je tak možné provádět změny s větší jistotou než při refaktorování kódu bez testů.

  7. Kontrola pokrytí.Jednotkové testy jsou užitečnější, když pokrývají větší část kódu.Je tak možné zjistit, které části kódu jsou testy ověřované.

  8. Oddělení jednotek od externích zdrojů.Knihovna DLL je obvykle závislá na jiných komponentách vyvíjeného systému jako ostatní knihovny DLL, databáze nebo vzdálené podsystémy.Je vhodné testovat každou jednotku odděleně od jejích závislostí.Externí komponenty také mohou testy zpomalovat.Během vývoje nemusí být další komponenty dokončené.

Vytvoření projektu testů nativního kódu

  1. V nabídce Soubor zvolte položku Nový, Projekt.

    V dialogovém okně rozbalte Nainstalované, Šablony, Visual C++, Test.

    Zvolte šablonu Projekt testů nativního kódu.

    V tomto návodu je projekt testu pojmenován NativeRooterTest.

    Creating a C++ Unit Test Project

  2. V novém projektu prozkoumejte soubor unittest1.cpp

    Test project with TEST_CLASS and TEST_METHOD

    Všimněte si, že:

    • Každý test je definován pomocí TEST_METHOD(YourTestName){...}.

      Není třeba psát konvenční podpis funkce.Podpis vytvoří makro TEST_METHOD.Makro generuje instanční funkci, která vrací void.Také vygeneruje statickou funkci, která vrací informace o testovací metodě.Tyto informace umožní Průzkumníku testů nalézt tuto testovací metodu.

    • Testovací metody jsou seskupeny do tříd pomocí TEST_CLASS(YourClassName){...}.

      Při spuštění testů je vytvořena instance třídy každého testu.Testovací metody jsou spouštěny v nespecifikovaném pořadí.Můžete definovat zvláštní metody, které jsou vyvolány před a po každém modulu, třídě nebo metodě.Další informace naleznete v tématu Uspořádání testů v jazyce C++.

  3. Ověřte, že jsou testy spuštěny v Průzkumníku testů:

    1. Vložte kód testu:

      TEST_METHOD(TestMethod1)
      {
      Assert::AreEqual(1,1);
      }
      

      Všimněte si, že třída Assert poskytuje několik statických metod, které můžete použít k ověření výsledků v testovacích metodách.

    2. V nabídce Test zvolte Spustit , Všechny testy.

      Test se sestaví a spustí.

      Zobrazí se Průzkumník testů.

      Test se zobrazí ve skupině Úspěšné testy.

      Unit Test Explorer with one passed test

Vytvoření projektu nespravované knihovny DLL

  1. Vytvořte projekt Visual C++ pomocí šablony Projekt Win32.

    V tomto návodu je projekt pojmenován RootFinder.

    Creating a C++ Win32 project

  2. V Průvodci aplikace Win32 zvolte DLL a Exportovat symboly.

    Možnost Exportovat symboly generuje užitečné makro, které můžete použít pro deklaraci exportovaných metod.

    C++ project wizard set for DLL and Export Symbols

  3. Deklarujte exportovanou funkci v hlavním soubor s příponou .h:

    New DLL code project and .h file with API macros

    Deklarátor __declspec(dllexport) zviditelní veřejné a chráněné členy třídy mimo knihovnu DLL.Další informace naleznete v tématu Používání příkazů dllimport a dllexport ve třídách jazyka C++.

  4. V hlavním souboru s příponou .cpp přidejte minimální tělo funkce:

    // Find the square root of a number.
    double CRootFinder::SquareRoot(double v)
    {
      return 0.0;
    }
    

Spojení projektu testu s projektem knihovny DLL

  1. Přidejte projekt knihovny DLL do odkazů na projekty testovacího projektu:

    1. Otevřete vlastnosti projektu testu a zvolte Společná nastavení, Rámec a odkazy.

      C++ project properties - Framework and References

    2. Zvolte Přidat nový odkaz.

      V dialogovém okně Přidat odkaz zvolte projekt knihovny DLL a zvolte Přidat.

      C++ project properties - Add New Reference

  2. V hlavním souboru s příponou .cpp jednotkového testu zahrňte soubor s příponou .h souboru kódu knihovny DLL:

    #include "..\RootFinder\RootFinder.h"
    
  3. Přidejte základní test, který používá exportované funkce:

    TEST_METHOD(BasicTest)
    {
    CRootFinder rooter;
    Assert::AreEqual(
    // Expected value:
    0.0, 
    // Actual value:
    rooter.SquareRoot(0.0), 
    // Tolerance:
    0.01,
    // Message:
    L"Basic test failed",
    // Line number - used if there is no PDB file:
    LINE_INFO());
    }
    
  4. Sestavte řešení.

    Nový test se zobrazí v Průzkumníku testů.

  5. V Průzkumníku testů zvolte položku Spustit všechny.

    Unit Test Explorer - Basic Test passed

Nastavili jste projekt testu a projekt s kódem a ověřili jste, že je možné spouštět testy, které spouští funkce projektu s kódem.Nyní můžete začít psát skutečné testy a kód.

Postupné rozšiřování testů a zajištění jejich úspěšného provedení

  1. Přidejte nový test:

    TEST_METHOD(RangeTest)
    {
      CRootFinder rooter;
      for (double v = 1e-6; v < 1e6; v = v * 3.2)
      {
        double actual = rooter.SquareRoot(v*v);
        Assert::AreEqual(v, actual, v/1000);
      }
    }
    

    Tip

    Doporučujeme neměnit testy, které byly úspěšné.Místo toho přidejte nový test, aktualizujte kód tak, aby byl test úspěšný, a potom přidejte další test atd.

    Když uživatelé změní své požadavky, zakažte testy, které již nejsou správné.Stejným inkrementálním způsobem vytvářejte nové testy po jednom a postupně zajistěte jejich úspěšné provedení.

  2. Sestavte řešení a pak v Průzkumníku testů zvolte Spustit všechny.

    Nový test skončí neúspěšně.

    The RangeTest fails

    Tip

    Ověřte, že každý test skončí neúspěšně ihned poté, co jste jej napsali.To vám pomůže se vyhnout snadné chybě ve vytvoření testu, který nikdy neskončí neúspěšně.

  3. Upravte testovaný kód tak, aby nový test skončil úspěšně:

    #include <math.h>
    ...
    double CRootFinder::SquareRoot(double v)
    {
      double result = v;
      double diff = v;
      while (diff > result/1000)
      {
        double oldResult = result;
        result = result - (result*result - v)/(2*result);
        diff = abs (oldResult - result);
      }
      return result;
    }
    
  4. Sestavte řešení a pak v Průzkumníku testů zvolte Spustit všechny.

    Oba testy skončily úspěšně.

    Unit Test Explorer - Range Test passed

    Tip

    Vyvíjejte kód postupným přidáváním jednoho testu za druhým.Po každé iteraci se ujistěte, že všechny testy skončí úspěšně.

Ladění testu, který skončil neúspěšně.

  1. Přidejte další test:

    #include <stdexcept>
    ...
    // Verify that negative inputs throw an exception.
    TEST_METHOD(NegativeRangeTest)
    {
      wchar_t message[200];
      CRootFinder rooter;
      for (double v = -0.1; v > -3.0; v = v - 0.5)
      {
        try 
        {
          // Should raise an exception:
          double result = rooter.SquareRoot(v);
    
          _swprintf(message, L"No exception for input %g", v);
          Assert::Fail(message, LINE_INFO());
        }
        catch (std::out_of_range ex)
        {
          continue; // Correct exception.
        }
        catch (...)
        {
          _swprintf(message, L"Incorrect exception for %g", v);
          Assert::Fail(message, LINE_INFO());
        }
      }
    }
    
  2. Sestavte řešení a zvolte Spustit všechny.

  3. Otevřete (nebo dvakrát klikněte) test, který skončil neúspěšně.

    Neúspěšný kontrolní výraz je zvýrazněn.Zpráva o neúspěchu je zobrazena v podokně podrobností Průzkumníku řešení.

    NegativeRangeTests failed

  4. Chcete-li zjistit, proč se test nezdařil, projděte funkci:

    1. Nastavte zarážku na začátku funkce SquareRoot.

    2. V místní nabídce neúspěšného testu zvolte Ladit vybrané testy.

      Když se provádění zastaví na zarážce, procházejte kód.

  5. Vložte následující kód do vyvíjené funkce:

    #include <stdexcept>
    ...
    double CRootFinder::SquareRoot(double v)
    {
        // Validate parameter:
        if (v < 0.0) 
        {
          throw std::out_of_range("Can't do square roots of negatives");
        }
    
  6. Všechny testy teď proběhly úspěšně.

    All tests pass

Refaktorování kódu bez změny testů

  1. Zjednodušte hlavní výpočet ve funkci SquareRoot:

    // old code:
    //   result = result - (result*result - v)/(2*result);
    // new code:
         result = (result + v/result)/2.0;
    
  2. Sestavte řešení a zvolte Spustit všechny, abyste zajistili, že nebyla zavedena žádná chyba.

    Tip

    Dobrá sada jednotkových testů dává jistotu, že při změnách kódu nebyly zavedeny žádné chyby.

    Oddělte refaktorování od ostatních změn.

Další kroky

  • Oddělení. Většina knihoven DLL je závislých na ostatních subsystémech, jako jsou databáze nebo jiné knihovny DLL.Tyto další součásti jsou často vyvíjeny souběžně.Abyste umožnili provedení jednotkového testování, i když ještě nejsou dostupné ostatní komponenty, je nutné zavést mock objekt nebo

  • Ověřovací testy sestavení. Je možné provádět testy na serverech sestavení v zadaných intervalech.Tím se zajistí, že nebudou zavedeny chyby při integraci práce několika členů týmu.

  • Testy vrácení se změnami. Je také možné přikázat, aby se některé testy prováděly před nahráním kódu každého člena týmu do správy zdrojového kódu.Tyto testy jsou obvykle podmnožinou úplné sady ověřovacích testů sestavení.

    Je také možné přikázat minimální úroveň pokrytí kódu.

Viz také

Úkoly

Návod: Vytvoření a použití dynamické knihovny (C++)

Koncepty

Import a export

Další zdroje

Přehled interoperability spravovaného/nespravovaného kódu

Ladění nativního kódu