Kako koristiti Moq za olakšavanje jediničnog testiranja na C #

Često trebamo napisati jedinične testove za kôd koji pristupa vanjskim resursima poput baze podataka ili datotečnog sustava datoteka. Ako takvi resursi nisu dostupni, jedini način da se osigura da se testovi mogu izvršiti je stvaranje lažnih objekata. U osnovi, crtajući se na lažnim implementacijama ovih temeljnih ovisnosti, možete testirati interakciju između metode koja se ispituje i njezinih ovisnosti. Tri najpopularnija rugljiva okvira za .Net programere su Rhino Mocks, Moq i NMock.

Među njima, Moq je možda najfleksibilniji i najjednostavniji za upotrebu. Moq okvir pruža elegantan način postavljanja, testiranja i provjere lažnih podataka. Ovaj članak predstavlja raspravu o Moq-u i kako se on može koristiti za izoliranje jedinica koda od njihovih ovisnosti.

Početak rada s Moqom

Moq možete koristiti za stvaranje lažnih objekata koji simuliraju ili oponašaju stvarni objekt. Moq se može koristiti za ismijavanje klasa i sučelja. Međutim, morate biti svjesni nekoliko ograničenja. Klase koje treba ismijavati ne mogu biti statične ili zapečaćene, a metoda koja se ismijava treba biti označena kao virtualna. (Imajte na umu da postoje zaobilaženja ovih ograničenja. Mogli biste se rugati statičkoj metodi koristeći, na primjer, obrazac dizajna adaptera.)

Prvi korak u korištenju Moq-a je njegova instalacija kako biste ga mogli koristiti u projektu jedinstvenog testa. Moq možete preuzeti s GitHub-a i dodati reference prema potrebi. Međutim, više volim instalirati Moq putem NuGet-a jer je i lakše i manje je vjerojatno da ćete propustiti reference. Moq možete instalirati pomoću sljedeće naredbe u naredbenom retku NuGet.

Install-Package Moq

Kako se rugati sučeljima pomoću Moq-a

Krenimo od ruganja sučelju. Sintaksa za stvaranje lažnog objekta pomoću klase Mock data je u nastavku.

Mock mockObjectType = novi Mock ();

Sada razmotrite sljedeće sučelje nazvano IAuthor.

javno sučelje IAuthor

    {

        int Id {get; postavljen; }

        string FirstName {get; postavljen; }

        niz Prezime_ {get; postavljen; }

    }

Koristeći Moq okvir, možete stvoriti lažni objekt, postaviti vrijednosti svojstava, navesti parametre i vratiti vrijednosti na pozive metode. Sljedeći isječak koda ilustrira kako možete stvoriti instancu iz sučelja IAuthor koristeći Moq.

var mock = novi Mock ();

Imajte na umu da Mock klasa pripada Moq okviru i sadrži generički konstruktor koji prihvaća vrstu sučelja koje želite stvoriti. Moq iskorištava lambda izraze, delegate i generike. Sve ovo čini korištenje okvira vrlo intuitivnim.

Sljedeći isječak koda pokazuje kako se možete rugati sučelju IAuthor i pružiti svojstvima ismijane instance odgovarajuće vrijednosti. Primijetite kako koristimo Assert za provjeru vrijednosti svojstava ismijane instance.

var autor = novi Mock ();

autor.SetupGet (p => p.Id) .Povraćaj (1);

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

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

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

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

Kako se rugati metodama pomoću Moq

Razmotrimo sada sljedeću klasu pod nazivom Article. Klasa Article sadrži samo jednu metodu koja se naziva GetPublicationDate koja prihvaća ID članka kao parametar i vraća datum objave članka.

javni razred Članak

    {

        javni virtualni DateTime GetPublicationDate (int articleId)

        {

            baciti novi NotImplementedException ();

        }

    }

Budući da metoda GetPublicationDate još nije implementirana u klasi Article, izrugivana je metoda kako bi trenutni datum vratio kao datum objave, kao što je prikazano u isječku koda koji je dat u nastavku.

var mockObj = novi Mock ();
mockObj.Setup (x => x.GetPublicationDate (It.IsAny ())). Vraća ((int x) => DateTime.Now);

Metoda postavljanja koristi se za definiranje ponašanja metode koja joj se prosljeđuje kao parametar. U ovom se primjeru koristi za definiranje ponašanja metode GetPublicationDate. Poziv na It.IsAny()implicira da će metoda GetPublicationDate prihvatiti parametar tipa integer; Itodnosi se na statičku klasu. Metoda povrata koristi se za specificiranje povratne vrijednosti metode koja je navedena u pozivu metode postavljanja. U ovom se primjeru metoda Povrati koristi za specificiranje povratne vrijednosti metode kao trenutni sistemski datum.

Moq vam omogućuje da provjerite je li pozvana određena metoda ili svojstvo. Sljedeći isječak koda to ilustrira.

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

Ovdje koristimo metodu Verify da bismo utvrdili je li GetPublicationDate pozvan na lažni objekt.

Kako se rugati metodama osnovne klase koristeći Moq

Razmotrite sljedeći dio koda. Ovdje imamo dvije klase - klasu RepositoryBase i klasu AuthorRepository koja je proširuje.

javna apstraktna klasa RepositoryBase

{

    javni virtualni bool IsServiceConnectionValid ()

    {

        // Neki kod

    }

}

javna klasa AuthorRepository: RepositoryBase

{

    javna praznina Spremi ()

    {

        if (IsServiceConnectionValid ())

        {

            // Neki kod

        }

    }

}

Sada pretpostavimo da želimo provjeriti je li veza s bazom podataka važeća. Međutim, možda nećemo htjeti testirati sav kôd unutar metode IsServiceConnectionValid. Na primjer, metoda IsServiceConnectionValid može sadržavati kod koji se odnosi na biblioteku treće strane. Ne bismo to htjeli testirati, zar ne? Evo gdje u pomoć dolazi metoda CallBase u Moqu. 

U ovakvim situacijama, kada imate metodu u osnovnoj klasi koja je nadjačana u ismijanom tipu, a morate se rugati samo osnovnoj verziji nadjačane metode, možete crtati na CallBaseu. Sljedeći isječak koda pokazuje kako možete stvoriti djelomični lažni objekt klase AuthorRepository postavljanjem svojstva CallBase na true.

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

mockObj.Setup (x => x.IsServiceConnectionValid ()). Vraća (true);

Moq okvir olakšava stvaranje lažnih objekata koji oponašaju ponašanje klasa i sučelja za testiranje, uz samo potrebnu funkcionalnost. Za više informacija o testiranju s lažnim porukama pogledajte ovaj sjajni članak Martina Fowlera.