Programmering

Slik bruker du Moq for å lette enhetstesting i C #

Vi trenger ofte å skrive enhetstester for kode som får tilgang til en ekstern ressurs, for eksempel en database eller et filfilsystem. Hvis slike ressurser ikke er tilgjengelige, er den eneste måten å sikre at testene kan utføres ved å lage mock-objekter. I hovedsak, ved å tegne på falske implementeringer av disse underliggende avhengighetene, kan du teste samspillet mellom metoden som testes og dens avhengighet. Tre av de mest populære mocking-rammene for .Net-utviklere er Rhino Mocks, Moq og NMock.

Blant disse kan Moq være den mest fleksible og enkle å bruke. Moq-rammeverket gir en elegant måte å sette opp, teste og verifisere spott. Denne artikkelen presenterer en diskusjon av Moq og hvordan den kan brukes til å isolere kodenheter fra deres avhengighet.

Komme i gang med Moq

Du kan bruke Moq til å lage mock-objekter som simulerer eller etterligner et ekte objekt. Moq kan brukes til å spotte både klasser og grensesnitt. Det er imidlertid noen begrensninger du bør være oppmerksom på. Klassene som skal spottes, kan ikke være statiske eller forseglet, og metoden som spottes, skal merkes som virtuell. (Merk at det er løsninger på disse begrensningene. Du kan spotte en statisk metode ved å benytte deg av adaptermønsteret, for eksempel.)

Det første trinnet i å bruke Moq er å installere den slik at du kan bruke den i ditt enhetstestprosjekt. Du kan laste ned Moq fra GitHub og legge til referanser etter behov. Imidlertid foretrekker jeg å installere Moq via NuGet fordi det er både lettere og mindre sannsynlig å savne referanser. Du kan installere Moq ved å bruke følgende kommando på NuGet-kommandolinjen.

Install-Package Moq

Hvordan spotte grensesnitt ved hjelp av Moq

La oss starte med å spotte et grensesnitt. Syntaksen for å lage et mock-objekt ved hjelp av Mock-klassen er gitt nedenfor.

Mock mockObjectType = ny Mock ();

Vurder nå følgende grensesnitt som heter IAuthor.

offentlig grensesnitt IAuthor

    {

int Id {get; sett; }

streng Fornavn {get; sett; }

streng Etternavn {get; sett; }

    }

Ved å bruke Moq-rammeverket kan du opprette et mock-objekt, angi eiendomsverdier, spesifisere parametere og returnere verdier på metodeanropene. Følgende kodebit illustrerer hvordan du kan opprette en forekomst fra IAuthor-grensesnittet ved hjelp av Moq.

var mock = new Mock ();

Merk at Mock-klassen tilhører Moq-rammeverket og inneholder en generisk konstruktør som godtar typen grensesnitt du vil lage. Moq utnytter lambdauttrykk, delegater og generiske legemidler. Alt dette gjør bruk av rammeverket veldig intuitivt.

Følgende kodebit viser hvordan du kan spotte IAuthor-grensesnittet og gi egenskapene til den spottede forekomsten de riktige verdiene. Legg merke til hvordan vi bruker Assert for å verifisere verdiene til egenskapene til den hånede forekomsten.

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);

Hvordan spotte metoder ved hjelp av Moq

La oss nå se på følgende klasse som heter Article. Artikkelklassen inneholder bare en metode kalt GetPublicationDate som godtar en artikkel-ID som parameter og returnerer publiseringsdatoen for artikkelen.

offentlig klasse Artikkel

    {

offentlig virtuell DateTime GetPublicationDate (int articleId)

        {

kaste nye NotImplementedException ();

        }

    }

Fordi GetPublicationDate-metoden ennå ikke er implementert i artikkelklassen, har metoden blitt spottet for å returnere gjeldende dato som publiseringsdato, som vist i kodebiten gitt nedenfor.

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

Oppsettmetoden brukes til å definere oppførselen til en metode som sendes til den som en parameter. I dette eksemplet brukes den til å definere oppførselen til GetPublicationDate-metoden. Oppfordringen til It.IsAny () innebærer at GetPublicationDate-metoden aksepterer en parameter av typen heltall; Den refererer til en statisk klasse. Returmetoden brukes til å spesifisere returverdien til metoden som er spesifisert i Setup-metoden. I dette eksemplet brukes returmetoden til å spesifisere returverdien til metoden som gjeldende systemdato.

Moq lar deg bekrefte om en bestemt metode eller en eiendom ble kalt. Følgende kodebit illustrerer dette.

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

Her bruker vi Bekreft-metoden for å avgjøre om GetPublicationDate ble kalt til det mock-objektet.

Hvordan spotte baseklassemetoder ved hjelp av Moq

Tenk på følgende kode. Vi har to klasser her - RepositoryBase-klassen og AuthorRepository-klassen som utvider den.

offentlig abstrakt klasse RepositoryBase

{

offentlig virtuell bool IsServiceConnectionValid ()

    {

// Noe kode

    }

}

public class AuthorRepository: RepositoryBase

{

offentlig ugyldig Lagre ()

    {

hvis (IsServiceConnectionValid ())

        {

// Noe kode

        }

    }

}

Anta at vi vil sjekke om databasetilkoblingen er gyldig. Imidlertid vil vi kanskje ikke teste all koden i IsServiceConnectionValid-metoden. For eksempel kan IsServiceConnectionValid-metoden inneholde kode som gjelder et tredjepartsbibliotek. Vi vil ikke teste det, ikke sant? Her er hvor CallBase-metoden i Moq kommer til unnsetning.

I situasjoner som dette, hvor du har en metode i baseklassen som er blitt overstyrt i den spottede typen, og du bare må spotte basisversjonen av den overstyrte metoden, kan du trekke på CallBase. Følgende kodebit viser hvordan du kan opprette et delvis mock-objekt fra AuthorRepository-klassen ved å sette CallBase-egenskapen til true.

var mockObj = new Mock () {CallBase = true};

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

Moq-rammeverket gjør det enkelt å lage mock-objekter som etterligner oppførselen til klasser og grensesnitt for testing, med akkurat den funksjonaliteten du trenger. For mer om testing med mocks, sjekk ut denne flotte artikkelen fra Martin Fowler.