Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
In questo argomento viene descritto come creare unit test per una libreria di collegamento dinamico di Visual C++ per le app della piattaforma UWP (Universal Windows Platform) con il framework di test Microsoft per C++. La libreria di collegamento RooterLib rammenta vagamente la teoria dei limiti di calcolo implementando una funzione che calcola una stima della radice quadrata di un numero specificato. La DLL può quindi essere inclusa in un'app UWP che mostra a un utente il lato divertente della matematica.
Questo argomento illustra come usare unit test come primo passaggio dell'attività di sviluppo Secondo questo approccio devi innanzitutto scrivere un metodo di test che verifica il comportamento specifico del sistema che stai testando, quindi scriverai il codice che supera il test. Apportando modifiche nell'ordine in cui sono presentate le procedure riportate di seguito, è possibile invertire questa strategia scrivendo prima il codice da testare e quindi gli unit test.
In questo argomento si creerà inoltre una soluzione di Visual Studio e progetti distinti per gli unit test e la DLL da testare. Puoi anche includere gli unit test direttamente nel progetto DLL oppure creare soluzioni separate per gli unit test e la DLL. Per suggerimenti sulla struttura da usare, vedere Aggiunta di unit test alle applicazioni C++ esistenti.
Creare la soluzione e il progetto unit test
Per iniziare, creare un nuovo progetto di test. Nel menu File scegliere Nuovo>Progetto. Nella finestra di dialogo Crea un nuovo progetto digitare "test" nella casella di ricerca e quindi impostare Linguaggio su C++. Scegli quindi App unit test (Windows universale) nell'elenco di modelli di progetto.

Nella finestra di dialogo Nuovo progetto espandere Installati>Visual C++ e scegliere Universale di Windows. Scegli quindi App unit test (Windows universale) nell'elenco di modelli di progetto.
Assegnare al progetto il nome
RooterLibTests, specificare il percorso, assegnare alla soluzione il nomeRooterLibe verificare che l'opzione Crea directory per soluzione sia selezionata.
Nel nuovo progetto aprire unittest1.cpp.

Tenere presente quanto segue:
Ogni test è definito tramite
TEST_METHOD(YourTestName){...}.Non è necessario scrivere una firma della funzione formale. La firma viene creata dalla macro TEST_METHOD. La macro genera un'istanza a una funzione che restituisce un valore nullo. Viene inoltre generata una funzione statica che restituisce informazioni sul metodo di test. Queste informazioni consentono ad Esplora test di individuare il metodo.
I metodi dei test vengono raggruppati in classi usando
TEST_CLASS(YourClassName){...}.Quando vengono eseguiti i test, viene creata un'istanza di ogni classe di test. I metodi di test vengono chiamati in un ordine non specificato. È possibile definire metodi speciali che vengono richiamati prima e dopo ogni modulo, classe, o metodo. Per altre informazioni, vedere Uso di Microsoft.VisualStudio.TestTools.CppUnitTestFramework.
Verificare che i test siano eseguiti in Esplora test
Inserire il codice di test:
TEST_METHOD(TestMethod1) { Assert::AreEqual(1,1); }Si noti che la classe
Assertfornisce diversi metodi statici che è possibile usare per verificare i risultati nei metodi di test.Scegliere Esegui dal menu Test, quindi Esegui tutto.
Il progetto di test viene compilato ed eseguito. Viene visualizzata la finestra di Esplora test con il test elencato in Test superati. Nel riquadro di riepilogo nella parte inferiore della finestra sono disponibili altri dettagli sul test selezionato.

Aggiungere il progetto di DLL alla soluzione
In Esplora soluzioni scegliere il nome della soluzione. Dal menu di scelta rapida scegliere Aggiungi e quindi Nuovo progetto. Nella finestra di dialogo Aggiungi un nuovo progetto impostare Linguaggio su C++ e digitare "DLL" nella casella di ricerca. Nell'elenco dei risultati scegliere App unit test (Windows universale - C++/CX).

Nella finestra di dialogo Aggiungi nuovo progetto scegliere DLL (app UWP).
Aggiungere il seguente codice al file RooterLib.h:
// The following ifdef block is the standard way of creating macros which make exporting // from a DLL simpler. All files within this DLL are compiled with the ROOTERLIB_EXPORTS // symbol defined on the command line. This symbol should not be defined on any project // that uses this DLL. This way any other project whose source files include this file see // ROOTERLIB_API functions as being imported from a DLL, whereas this DLL sees symbols // defined with this macro as being exported. #ifdef ROOTERLIB_EXPORTS #define ROOTERLIB_API __declspec(dllexport) #else #define ROOTERLIB_API __declspec(dllimport) #endif //ROOTERLIB_EXPORTS class ROOTERLIB_API CRooterLib { public: CRooterLib(void); double SquareRoot(double v); };I commenti spiegano il blocco ifdef non solo allo sviluppatore della DLL, ma a chiunque faccia riferimento alla DLL nel progetto. È possibile aggiungere il simbolo di ROOTERLIB_EXPORTS alla riga di comando usando le proprietà di progetto della DLL.
La classe
CRooterLibdichiara un costruttore e il metodo estimativoSqareRoot.Aggiungere il simbolo di ROOTERLIB_EXPORTS alla riga di comando.
In Esplora soluzioni selezionare il progetto RooterLib e quindi scegliere Proprietà dal menu di scelta rapida.

Nella finestra di dialogo Pagina delle proprietà di RooterLib espandere Proprietà di configurazione, espandere C++ e scegliere Preprocessore.
Scegliere <Modifica...> dall'elenco Definizioni del preprocessore e quindi aggiungere
ROOTERLIB_EXPORTSnella finestra di dialogo Definizioni del preprocessore.
Aggiungere implementazioni minime delle funzioni dichiarate. Aprire RooterLib.cpp e aggiungere il codice seguente:
// constructor CRooterLib::CRooterLib() { } // Find the square root of a number. double CRooterLib::SquareRoot(double v) { return 0.0; }
Rendere visibili le funzioni dll al codice di test
Aggiungere RooterLib al progetto RooterLibTests.
In Esplora soluzioni selezionare il progetto RooterLibTests e quindi scegliere Aggiungi>Riferimento dal menu di scelta rapida.
Nella finestra di dialogo Aggiungi riferimento scegliere Progetti. Selezionare quindi l'elemento RouterLib.
Includere il file di intestazione RooterLib in unittest1.cpp.
Aprire unittest1.cpp.
Aggiungere il codice seguente sotto la riga
#include "CppUnitTest.h":#include "..\RooterLib\RooterLib.h"
Aggiungere un test che usa la funzione importata. Aggiungere il codice seguente a unittest1.cpp:
TEST_METHOD(BasicTest) { CRooterLib 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()); }Compilare la soluzione.
Il nuovo test viene visualizzato in Esplora test nel nodo Test non eseguiti.
In Esplora test scegliere Esegui tutto.

È stato installato il test e i progetti di codice, e verificato che sia possibile eseguire test che eseguono funzioni nel progetto di codice. Ora è possibile iniziare a scrivere test e codici reali.
Incrementare i test in maniera iterativa e fare in modo che siano superati
Aggiungere un nuovo test:
TEST_METHOD(RangeTest) { CRooterLib rooter; for (double v = 1e-6; v < 1e6; v = v * 3.2) { double expected = v; double actual = rooter.SquareRoot(v*v); double tolerance = expected/1000; Assert::AreEqual(expected, actual, tolerance); } };Suggerimento
È consigliabile non modificare i test che siano stati superati. Al contrario, aggiungere un nuovo test, aggiornare il codice in modo che il test passi e quindi aggiungere un altro test, e così via.
Quando gli utenti modificano i requisiti, disabilitare i test che non sono più corretti. Scrivere nuovi test e farli funzionare uno alla volta, nello stesso modo incrementale.
In Esplora test scegliere Esegui tutto.
Il test ha esito negativo.

Suggerimento
Verificare che ogni test non venga superato subito dopo averlo scritto. Questo consente di evitare il semplice errore di scrivere un test che riesce sempre.
Modifica il codice sottoposto a test in modo che il nuovo test venga superato. Aggiungere quanto segue a RooterLib.cpp:
#include <math.h> ... // Find the square root of a number. double CRooterLib::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; }Compilare la soluzione e quindi scegliere Esegui tutto in Esplora test.
Entrambi i test vengono superati.
Suggerimento
Sviluppare il codice aggiungendo un test alla volta. Assicurarsi che tutti i test vengano superati dopo ogni iterazione.
Eseguire il debug di un test non superato
Aggiungere un altro test a unittest1.cpp:
// Verify that negative inputs throw an exception. TEST_METHOD(NegativeRangeTest) { wchar_t message[200]; CRooterLib rooter; for (double v = -0.1; v > -3.0; v = v - 0.5) { try { // Should raise an exception: double result = rooter.SquareRoot(v); swprintf_s(message, L"No exception for input %g", v); Assert::Fail(message, LINE_INFO()); } catch (std::out_of_range ex) { continue; // Correct exception. } catch (...) { swprintf_s(message, L"Incorrect exception for %g", v); Assert::Fail(message, LINE_INFO()); } } };In Esplora test scegliere Esegui tutto.
Il test ha esito negativo. Scegliere il nome del test in Esplora test. L'asserzione fallita viene evidenziata. Il messaggio di errore è visibile nel riquadro dei dettagli di Esplora test.

Per capire perché il test non riesce, scorrere la funzione:
Imposta un punto di interruzione all'inizio della funzione
SquareRoot.Dal menu di scelta rapida del test non superato, scegliere Esegui debug test selezionati.
Quando l'esecuzione si arresta in corrispondenza del punto di interruzione, eseguire il codice un'istruzione alla volta.
Aggiungere codice a RooterLib.cpp per intercettare l'eccezione:
#include <stdexcept> ... double CRooterLib::SquareRoot(double v) { //Validate the input parameter: if (v < 0.0) { throw std::out_of_range("Can't do square roots of negatives"); } ...In Esplora test scegliere Esegui tutto per testare il metodo corretto e assicurarsi di non aver introdotto una regressione.
Tutti i test vengono ora superati.

Effettuare il refactoring del codice senza modificare i test
Semplificare il calcolo centrale nella funzione
SquareRoot:// old code //result = result - (result*result - v)/(2*result); // new code result = (result + v/result) / 2.0;Scegliere Esegui tutto per testare il metodo di cui è stato eseguito il refactoring e assicurarsi di non aver introdotto una regressione.
Suggerimento
Un set stabile di unit test corretti indica con sufficiente sicurezza che non sono stati introdotti bug in fase di modifica del codice.
Mantenere il refactoring separato da altre modifiche.