Programmering

Sådan bruges Moq til at lette enhedstest i C #

Vi har ofte brug for at skrive enhedstest for kode, der får adgang til en ekstern ressource, såsom en database eller et filfilsystem. Hvis sådanne ressourcer ikke er tilgængelige, er den eneste måde at sikre, at testene kan udføres ved at oprette mock-objekter. I det væsentlige kan du teste interaktionen mellem metoden, der testes, og dens afhængigheder ved at trække på falske implementeringer af disse underliggende afhængigheder. Tre af de mest populære mocking-rammer for .Net-udviklere er Rhino Mocks, Moq og NMock.

Blandt disse kan Moq være den mest fleksible og nemme at bruge. Moq-rammen giver en elegant måde at oprette, teste og verificere mocks på. Denne artikel præsenterer en diskussion af Moq, og hvordan den kan bruges til at isolere kodeenheder fra deres afhængigheder.

Kom godt i gang med Moq

Du kan bruge Moq til at oprette mock-objekter, der simulerer eller efterligner et rigtigt objekt. Moq kan bruges til at spotte begge klasser og grænseflader. Der er dog et par begrænsninger, du skal være opmærksom på. Klasser, der skal spottes, kan ikke være statiske eller forseglede, og metoden, der spottes, skal markeres som virtuel. (Bemærk, at der er løsninger på disse begrænsninger. Du kan spotte en statisk metode ved f.eks. At udnytte adapterens designmønster.)

Det første trin i brugen af ​​Moq er at installere det, så du kan bruge det i dit enhedstestprojekt. Du kan downloade Moq fra GitHub og tilføje referencer efter behov. Imidlertid foretrækker jeg at installere Moq via NuGet, fordi det både er lettere og mindre sandsynligt at gå glip af referencer. Du kan installere Moq ved hjælp af følgende kommando på NuGet-kommandolinjen.

Installationspakke Moq

Sådan mockes grænseflader ved hjælp af Moq

Lad os starte med at spotte en grænseflade. Syntaksen til oprettelse af et mock-objekt ved hjælp af Mock-klassen er angivet nedenfor.

Mock mockObjectType = ny Mock ();

Overvej nu følgende grænseflade ved navn IAuthor.

offentlig grænseflade IAuthor

    {

int Id {get; sæt; }

streng Fornavn {get; sæt; }

streng Efternavn {get; sæt; }

    }

Ved hjælp af Moq-rammen kan du oprette et mock-objekt, indstille egenskabsværdier, angive parametre og returnere værdier på metodeopkaldene. Følgende kodestykke illustrerer, hvordan du kan oprette en instans fra IAuthor-grænsefladen ved hjælp af Moq.

var mock = ny Mock ();

Bemærk, at Mock-klassen tilhører Moq-rammen og indeholder en generisk konstruktør, der accepterer den type interface, du vil oprette. Moq drager fordel af lambda-udtryk, delegerede og generiske lægemidler. Alt dette gør brug af rammen meget intuitiv.

Følgende kodestykke viser, hvordan du kan spotte IAuthor-grænsefladen og give egenskaberne til den spottede forekomst med de relevante værdier. Bemærk, hvordan vi bruger Assert til at verificere værdierne for egenskaberne for den spottede forekomst.

var forfatter = ny Mock ();

author.SetupGet (p => p.Id) .Returns (1);

author.SetupGet (p => p.FirstName) .Returns ("Joydip");

author.SetupGet (p => p.LastName) .Returns ("Kanjilal");

Assert.AreEqual (“Joydip”, forfatter.Object.FirstName);

Assert.AreEqual (“Kanjilal”, forfatter.Object.LastName);

Sådan nar man metoder ved hjælp af Moq

Lad os nu overveje følgende klasse med navnet Article. Artikelklassen indeholder kun en metode kaldet GetPublicationDate, der accepterer en artikel-id som parameter og returnerer artikelens publiceringsdato.

offentlig klasse artikel

    {

offentlig virtuel DateTime GetPublicationDate (int articleId)

        {

smid ny NotImplementedException ();

        }

    }

Da GetPublicationDate-metoden endnu ikke er implementeret i artikelklassen, er metoden mokret for at returnere den aktuelle dato som offentliggørelsesdatoen, som vist i nedenstående kodestykke.

var mockObj = ny Mock ();
mockObj.Setup (x => x.GetPublicationDate (It.IsAny ())). Returnerer ((int x) => DateTime.Now);

Opsætningsmetoden bruges til at definere opførslen for en metode, der sendes til den som en parameter. I dette eksempel bruges det til at definere adfærden for metoden GetPublicationDate. Opkaldet til It.IsAny () indebærer, at GetPublicationDate-metoden accepterer en parameter af typen heltal; Det henviser til en statisk klasse. Metoden Returnerer bruges til at specificere returværdien for den metode, der er angivet i kaldet Setup-metode. I dette eksempel bruges metoden Retur til at specificere metodens returværdi som den aktuelle systemdato.

Moq giver dig mulighed for at kontrollere, om en bestemt metode eller en ejendom blev kaldt. Følgende kodestykke illustrerer dette.

mockObj.Verify (t => t.GetPublicationDate (It.IsAny ()));

Her bruger vi verificeringsmetoden til at afgøre, om GetPublicationDate blev kaldt på det mock-objekt.

Sådan spotter du baseklassemetoder ved hjælp af Moq

Overvej følgende stykke kode. Vi har to klasser her - klassen RepositoryBase og klassen AuthorRepository, der udvider den.

offentlig abstrakt klasse RepositoryBase

{

offentlig virtuel bool IsServiceConnectionValid ()

    {

// Noget kode

    }

}

public class AuthorRepository: RepositoryBase

{

offentlig tomrum Gem ()

    {

hvis (IsServiceConnectionValid ())

        {

// Noget kode

        }

    }

}

Antag nu, at vi vil kontrollere, om databaseforbindelsen er gyldig. Vi ønsker dog muligvis ikke at teste al koden inde i IsServiceConnectionValid-metoden. For eksempel kan IsServiceConnectionValid-metoden indeholde kode, der vedrører et tredjepartsbibliotek. Vi ønsker ikke at teste det, ikke? Her er hvor CallBase-metoden i Moq kommer til undsætning.

I situationer som denne, hvor du har en metode i baseklassen, der er blevet tilsidesat i den spottede type, og du kun skal spotte basisversionen af ​​den overstyrede metode, kan du trække på CallBase. Følgende kodestykke viser, hvordan du kan oprette et delvis mock-objekt fra klassen AuthorRepository ved at indstille egenskaben CallBase til sand.

var mockObj = ny Mock () {CallBase = sand};

mockObj.Setup (x => x.IsServiceConnectionValid ()). Returnerer (sand);

Moq-rammen gør det let at oprette mock-objekter, der efterligner klasser og grænseflades adfærd til test med netop den funktionalitet, du har brug for. For mere om test med mocks, se denne fantastiske artikel fra Martin Fowler.