BLOGas.lt
Sukurk savo BLOGą Kitas atsitiktinis BLOGas

Modulių testų rekomendacijos – 13 modulių testų rašymo taisyklių

Parašė Sergejus | 2011-07-31 18:50

Per paskutines dvi savaites teko rašyti ypatingai daug modulių testų (angl. unit tests) ir net pavyko pasiekti „išsvajotą“ 100% kodo aprėptį (angl. code coverage). Iš to gimė mintis parašyti kelių straipsnių ciklą apie rekomendacijas rašant modulių testus.

Modulių testų rekomendacijos – įrankiai ir aplinkos paruošimas
Modulių testų rekomendacijos – 13 modulių testų rašymo taisyklių

Praeitoje dalyje mes išnagrinėjome pagrindinius įrankius, skirtus modulių testavimui bei aptarėme aplinkos paruošimą. Šiame straipsnyje pateiksiu 13 modulių testų rašymo taisyklių, kurių pats prisilaikau jau keletą metų.

ATNAUJINTA

Atsižvelgiant į skaitytojų siūlymus (tiek tinklaraščio komentaruose, tiek Facebook), atnaujinau modulių testų rašymo taisykles.

13 modulių testų rašymo taisyklių

  1. Modulių testų rašymas tai irgi yra programavimas, todėl taikytinos visos standartinės kodo rašymo rekomendacijos
  2. Svarbiausias dalykas kuris turi būti ištestuotas – verslo logika
  3. Reikia turėti pakankamai modulių testų: nei per mažai, nei per daug
  4. Kiekvienas modulių testas turi tikrinti vieną ir tik vieną funkcionalumą
  5. Pagal galimybes reikia izoliuoti testuojamą logiką nuo išorinių resursų (naudojant netikrus objektus ir elgsenos aprašymą (angl. mocking), jeigu nepavyksta to padaryti, dažniausiai tai reiškia dizaino problemą kode ar statinių klasių panaudojimą
  6. Modulių testų vykdymas turi būti greitas
  7. Testų rezultatai tūri būti stabilūs ir determinuoti, tai yra visą laiką grąžinti tą patį rezultatą
  8. Modulių testų rašymo metu naudokite bazinę klasę bei pagalbinius metodus, bet jokių būdų nekvieskite tiesiogiai kitų testų
  9. Jeigu vienos klasės testai turi tą pačią sukūrimo / išvalymo logiką, naudokite specialiai tam skirtas konstrukcijas (Init, SetUp ir panašiai, priklausomai nuo pasirinkto modulių testų karkaso)
  10. Testuokite tik viešas (angl. public) ir vidinio naudojimo (angl. internal) klases, jeigu atsiranda poreikis testuoti privačius metodus (angl. private), dažniausiai tai reiškia šį funkcionalumą reikia iškelti į atskirą klasę
  11. Testo pradžioje apibrėžkite visus parametrus kaip kintamuosius, suteikiant jiems prasmingus pavadinimus
  12. Geriausias būdas dirbti su resursais – naudoti struktūrą try-finaly Kaip teisingai buvo pastebėta kelių skaitytojų – tai labiau liečia integracijų testus, todėl nusprendžiau išimti iš sąrašo
  13. Visi testai turi tenkinti [Arrange]-Act-Assert stilių, kur Arrange dalis nėra privaloma
  14. Testų pavadinimai turėtų pilnai nusakyti sąlygas, testuojamą objektą bei laukiamą rezultatą, pavyzdžiui galima naudoti tokį modulių testų vardų sudarymo šabloną: [Condition][Object][ExpectedResult][Action/Method]

Tikriausiai sutiksite, didžioji dalis aukščiau išvardintų taisyklių yra tiek logiškos, tiek savaime suprantamos. Paskutines 3 taisykles paaiškinsiu dviem pavyzdžiais:

public void Given_Not_Empty_String_It_Is_Correctly_Reversed()
{
  // Arrange
  var text = "Test text";
  var reversedText = "txet tseT";

  // Act  
  var result = StringHelper.Reverse(text);

  // Assert
  Assert.AreEqual(reversedText, result);
}
public void Given_Not_Existing_Directory_Path_Writer_Sucessfully_Creates_Directory_On_Write()
{
  // Arrange
  var exists = true;
  var doesNotExist = false;
  var dirPath = Path.GetTempPath();
  var text = "Test text";
  var fileSystem = new Mock<IFileSystem>();
  var writer = new FileWriter(fileSystem.Object);

  fileSystem.Setup(fs => fs.CreateDirectoryIfNotExists(It.IsAny<string>())

  // Act
  writer.Write(dirPath, text);

  // Assert
  fileSystem.Verify(fs => fs.CreateDirectoryIfNotExists(dirPath), Times.Once());
}

Arrange dalyje apibrėžiame visus reikalingus objektus ir parametrus bei esant poreikiui aprašome netikrus objektus ir reikalingą jų elgseną. Act dalyje iškviečiame testuojamą metodą su norimais parametrais. Assert dalyje patikriname vieną iš dviejų: arba paprastą Assert sąlygą, arba netikro objekto elgseną. Galiausiai, atkreipkite dėmesį į metodo pavadinimus – vien juos perskaičius galima tiksliai pasakyti kas daroma, esant kokioms pradinėms sąlygoms ir kokio rezultato tikimės.

Iš patirties galiu pasakyti, kad šios taisyklės ženkliai padeda programuotojams be didelės modulių testavimo patirties žengti pirmus žingsnius. Kitoje dalyje aptarsime ideologinius skirtumus tarp modulių testų ir integracijų testų.

Rodyk draugams

Modulių testų rekomendacijos – įrankiai ir aplinkos paruošimas

Parašė Sergejus | 2011-07-27 21:58

Per paskutines dvi savaites teko rašyti ypatingai daug modulių testų (angl. unit tests) ir net pavyko pasiekti „išsvajotą“ 100% kodo aprėptį (angl. code coverage). Iš to gimė mintis parašyti kelių straipsnių ciklą apie rekomendacijas rašant modulių testus.

Įrankiai

Pradėsime nuo pagrindinių bibliotekų (labai rekomenduoju šiems tikslams naudotis NuGet):

  • NUnit – paskutiniu metu naudoju kaip pagrindinį modulių testų karkasą, iš alternatyvų galite pasirinkti: MSTest, xUnit, MbUnit, MSpec.
  • Moq – populiariausia netikrų objektų kūrimo bei elgsenos aprašymo (angl. mocking) biblioteka, iš alternatyvų galite pasirinkti: Rhino Mocks, Typemock, JustMock.
  • AutoFixture – greitai populiarėjanti testinių duomenų generavimo biblioteka, iš alternatyvų galite pasirinkti: NBuilder.
  • ReSharper Unit Test Runner – viena patogiausių modulių testų vykdymo aplinkų (eina kartu su ReSharper), iš alternatyvų galite pasirinkti: MS Test Runner, TestDriven.NET, Gallio.
  • dotCover – naujas kodo aprėpties analizės įrankis (integruojamas su ReSharper, bet perkamas atskirai), iš alternatyvų galite pasirinkti: NCover, PartCover.

Aplinkos paruošimas

Turint po ranka visas reikalingas bibliotekas, pats laikas pereiti prie aplinkos paruošimo. Man pasiteisino tokia langų schema:

screen

Kairėje pusėje yra testuojama klasė (angl. System Under Test, SUT), o dešinėje – testai. Priklausomai nuo to, kiek monitorių turite, modulių testų vykdymo langas gali dinamiškai atsirasti lango apačioje arba gali būti užfiksuotas per pusę antro monitoriaus.

Kitas svarbus aspektas – greiti klavišai, skirti paleisti visus / vieną testą, praleisti aprėpties analizę ir pan. Kadangi dažnas testų paleidimas yra neatsiejama testų rašymo dalis, žymiai efektyviau išmokti greituosius klavišus ir naudotis jais, o ne spaudinėti grafinius mygtukus (panašiai, kaip yra su Ctrl + Shift + B :) ).

 

Štai mes ir esame pasiruošę rašyti modulių testus. Kitoje dalyje aš aptarsiu modulių testų vardų sudarymo rekomendacijas, kurias surinkau ir apibendrinau per keletą paskutinių metų.

Rodyk draugams

ASP.NET greitaveikos optimizavimo įrankiai

Parašė Sergejus | 2011-07-17 17:23

Ryšium su tam tikrais darbais, nusprendžiau surašyti dėmesio vertus įrankius, skirtus ASP.NET puslapių greitaveikos optimizavimui. Jeigu žinote daugiau įrankių – rašykite komentaruose!

  • YSlow ir Page Speed – ko gero populiariausi optimizavimo įrankiai, kurie ne tik įvertina jūsų puslapio greitaveiką, bet ir pateikia patarimus kaip galima ją (greitaveiką) pagerinti;
  • SenSEO ir SEO Toolkit – įvertina jūsų puslapių atitikimą paieškos variklių optimizavimo (angl. Search Engine Optimization, SEO) kriterijui;
  • SmushIt ir PunyPNG – online įrankiai skirti paveiksliukų optimizavimui, panaikinant meta informaciją bei vykdant papildomą suspaudimą be kokybės praradimo;
  • Image Optimizer – Visual Studio įskiepys skirtas paveiksliukų optimizavimui, panaudojant SmushIt ir PunyPNG servisus;
  • Ajax Minifier, YUI Compressor ir Closure Compiler – populiariausi JavaScript ir CSS minifikavimo (optimizavimo) įrankiai;
  • FileBundler, SquishIt – bibliotekos, skirtos susijusių failų apjungimui į vieną (JavaScript, CSS ir pan.);
  • Windows Azure CDN Helpers – pagalbinė klasė darbui su CDN;
  • Sprite and Image Optimization Framework – biblioteka, mokanti iš katalogo su paveiksliukais pagaminti vieną bendrą paveiksliuką (angl. Sprite) ir susijusį CSS failą;
  • Straipsnis, aprašantis HTTP kompresijos konfigūravimą IIS7.

Rodyk draugams

Web aplikacijų veikimo statistikos rinkimas ir analizė

Parašė Sergejus | 2011-07-10 22:22

Dažnai Web aplikacijų stebėjimas susiveda vien į pranešimų apie klaidas analizę. Dar geriau būtų turėti ir tam tikrą statistinę informaciją apie Web aplikacijos veikimą, pavyzdžiui, lėčiausiai besikraunančius puslapius, puslapius su daugiausia klaidų, populiariausius puslapius ir panašiai. Tokia informacija leidžia kur kas geriau įsivaizduoti realią situaciją ir kartais padeda net užbėgti problemoms už akių.

Norėdami pradėti kaupti ir analizuoti Web aplikacijų veikimo statistiką, reikia:

  • suinstaliuoti IIS modulius HTTP Logging ir Logging Tools;
  • įjungti žurnalizavimą (angl. logging) norimai Web aplikacijai;
  • pasinaudoti programa Log Parser duomenų gavimui bei statistikos paruošimui.

IIS modulių instaliavimas

Norėdami suinstaliuoti naujus IIS modulius:

  • Control Panel pasirinkite Programs and Features bei paspauskite Turn Windows features on or off;
  • nueikite į Internet Information ServicesWorld Wide Web ServicesHealth and Diagnostics bei pažymėkite HTTP Logging ir Logging Tools;
    image
  • paspauskite OK ir sulaukite modulio instaliavimo pabaigos.

Žurnalizavimo įjungimas

Norėdami įjungti ir sukonfigūruoti IIS žurnalizavimą:

  • nueikite į Internet Information Services Manager (intmgr) ir pasirinkite norimą Web aplikaciją;
  • paspauskite du kartus ant Logging;
    image
  • atsiradusiame lange Actions skiltyje paspauskite Enable;
  • palikite visus nustatymus pagal nutylėjimą ir paspauskite Apply;
    image
  • atkreipkite dėmesį kur bus saugoma informacija (%SystemDrive%\inetpub\logs\LogFiles), patogumo dėlei rekomenduoju pakeisti katalogą (pvz., D:\Logs);
  • norėdami pamatyti kokia informacija bus renkama, paspauskite mygtuką Select Fields.
    image

Duomenų gavimas ir statistikos paruošimas

Darbui su IIS žurnalu bus reikalinga nemokama programa iš Microsoft – Log Parser 2.2. Log Parser darbui su duomenimis naudoja į SQL panašią sintaksę, žemiau pateiksiu keletą pavyzdžių.

Top 10 puslapių su klaida HTTP500

logparser -i iisw3c "select top 10 cs-uri-stem as url, count(cs-uri-stem) as count from D:\Logs\ex110624.log where sc-status >= 500 group by url order by count(url) desc"

Top 10 puslapių kurie kraunasi ilgiau nei 2 sekundes

logparser -i iisw3c "select top 10 cs-uri-stem as url, avg(time-taken) as responsetime from D:\Logs\ex110624.log where extract_extension(cs-uri-stem) in (’asp’;'aspx’) group by url having responsetime > 2000 order by responsetime desc"

Top 10 populiariausių Web aplikacijų

logparser -i iisw3c "select top 10 substr(extract_prefix(cs-uri-stem, 1, ‘/’),1) as application, count(application) as count from D:\Logs\ex110624.log where extract_extension(cs-uri-stem) in (’asp’;'aspx’;’svc’;”) group by application, application order by count(application) desc"

Bonusas – statistikos rinkimo automatizavimas

Kaip matote, Web aplikacijų statistikos gavimas yra pakankamai paprasta užduotis, tereikia aprašyti tinkamas užklausas. Sekantis žingsnis galėtų būti aplikacijos sukūrimas, kuri Log Parser pagalba surinktų visą reikalingą statistiką ir pateiktų patogiu formatu. Šiuo tikslu aš sukūriau labai paprastą IisLogParser klasę:

public class IisLogParser
{
    private readonly string _logParserPath;

    public IisLogParser()
        : this("logparser.exe")
    {
    }

    public IisLogParser(string logParserPath)
    {
        _logParserPath = logParserPath;
    }

    public IEnumerable<string> ParseLog(string query)
    {
        var tmpFilePath = Path.GetTempFileName();
        try
        {
            query = query.Replace(" from ", " into " + tmpFilePath + " from ");
            var processInfo = new ProcessStartInfo
            {
                FileName = _logParserPath,
                Arguments = "-i iisw3c -o csv \"" + query + "\" -tabs:on -headers:off",
                CreateNoWindow = true,
                WindowStyle = ProcessWindowStyle.Hidden,
                UseShellExecute = false,
            };
            var proc = new Process { StartInfo = processInfo };

            proc.Start();
            proc.WaitForExit();

            if (new FileInfo(tmpFilePath).Length == 0)
            {
                throw new Exception("Output file is empty. Check query for correctness.");
            }

            return File.ReadAllLines(tmpFilePath);
        }
        finally
        {
            if (File.Exists(tmpFilePath))
            {
                File.Delete(tmpFilePath);
            }
        }
    }
}

Kaip matote, aš pasinaudojau Log Parser galimybe eksportuoti duomenis CSV formatu ir grąžinu eilučių sąrašą. Šios klasės panaudojimas galėtų atrodyti taip (naudojama prieš tai aprašyta užklausa Top 10 puslapių su klaida HTTP500):

class Program
{
    private const string LogPath = @"D:\Logs\ex110624.log";

    static void Main()
    {
        var logParser = new IisLogParser(@"c:\Program Files (x86)\Log Parser 2.2\LogParser.exe");

        var query = String.Format(
            "select top {0} cs-uri-stem as url, count(cs-uri-stem) as count " +
            "from {1} where sc-status >= 500 " +
            "group by url " +
            "order by count(url) desc", 10, LogPath);

        var result = from item in logParser.ParseLog(query)
                     let values = SplitValues(item)
                     select new
                     {
                         Url = values[0],
                         Count = Int32.Parse(values[1])
                     };
    }

    private static string[] SplitValues(string item)
    {
        return item.Split(new[] { ",\t" }, StringSplitOptions.None);
    }
}

Pabaigai…

Kaip tinkamai pasinaudoti šia informacija? Aš, pavyzdžiui, sukūriau Web aplikaciją kuri paeiliui rodo įvairiausią mūsų Web serverio statistiką. Kitą savaitę planuoju paleisti ją darbe ant televizoriaus ekrano ir taip vizualizuoti mūsų potencialias problemas. O kaip jus panaudotume tokius duomenis?

Rodyk draugams

Ketverti metai kaip MVP

Parašė Sergejus | 2011-07-02 16:52

Vakar gavau man labai svarbų laišką:

Dear Sergejus Barinovas,
Congratulations! We are pleased to present you with the 2011 Microsoft® MVP Award! This award is given to exceptional technical community leaders who actively share their high quality, real world expertise with others. We appreciate your outstanding contributions in Windows Azure technical communities during the past year.

Rodyk draugams