Hello, Habr!
My name is Maxim Ponomarenko and I am a developer at Sportmaster. I have 10 years of experience in the IT field. I started my career in manual testing and then switched to database development. For the last 4 years, accumulating knowledge gained in testing and development, I have been involved in automating testing at the database level.
I have been part of the Sportmaster team for just over a year and am working on automated testing for a major project. In April, my teammates from Sportmaster Lab and I presented at a conference in Krasnodar; my presentation was titled 'Unit-tests in databases,' and I now want to share it with you. There will be a lot of text, so I decided to split the presentation into two posts. In the first, we will discuss automated tests and testing in general, and in the second, I will go into more detail about our unit-testing system and the results of its application.
Let's start with a bit of boring theory. What is automated testing? It is testing conducted by software tools, and in modern IT, it is increasingly being used in software development. This is because companies are growing, their information systems are expanding, and consequently, the amount of functionality that needs to be tested is also increasing. Performing manual testing is becoming more and more cumbersome.
I worked at a large company where releases occurred every two months. During this time, a whole month was spent having a dozen testers manually check functionality. Thanks to the implementation of automation by a small team of developers, we managed to reduce testing time to 2 weeks over the course of a year and a half. We not only increased the speed of testing but also improved its quality. Automated tests are run regularly and they always perform the entire set of checks programmed into them, which means we eliminate human error.
In modern IT, it is characteristic that a developer may be required not only to write product code but also to write unit tests that verify this code.
Men hvad gør man, hvis dit system primært er baseret på serverlogik? Der findes ikke nogen universel løsning eller best practices på markedet. Som regel løser virksomheder dette problem ved at skabe deres eget skræddersyede testsystem. Et sådant skræddersyet automatiseret testsystem blev oprettet i vores projekt, og jeg vil tale om det i mit foredrag.

Test af loyalitet
Lad os først tale om projektet, hvor vi implementerede et automatiseret testsystem. Vores projekt er et loyalitetssystem for Sportmaster (for øvrigt har vi allerede skrevet om det i ).
Hvis din virksomhed er stor nok, vil dit loyalitetssystem have tre standardegenskaber:
- Dit system vil være højtydende
- Dit system vil indeholde komplekse beregningsprocesser
- Dit system vil blive aktivt videreudviklet.
Lad os tage det i rækkefølge... I alt, når vi ser på alle Sportmasters brands, har vi mere end 1000 butikker i Rusland, Ukraine, Kina, Kasakhstan og Hviderusland. Der foretages omkring 300.000 køb dagligt i disse butikker. Det vil sige, at der i vores system kommer 3-4 kvitteringer hvert sekund. Naturligvis er vores loyalitetssystem højtydende. Og da det bliver aktivt brugt, skal vi levere de højeste standarder for dets kvalitet, for enhver fejl i softwaren medfører store økonomiske, omdømmemæssige og andre tab.
Samtidig kører der mere end hundrede forskellige kampagner hos Sportmaster. Kampagnerne er meget forskellige: der er varekampagner, kampagner knyttet til ugedagen, kampagner knyttet til bestemte butikker, kampagner baseret på kvitteringsbeløbet og kampagner baseret på antallet af varer. Alt i alt, en del af en udfordring. Kunderne har bonusser og promo-koder, der bruges ved køb. Alt dette fører til, at beregningen af enhver ordre er en ret kompliceret opgave.
Algoritmen, der håndterer ordrebehandling, er virkelig forfærdelig og kompleks. Enhver ændring i denne algoritme er en ret risikabel affære. Det viste sig, at selv de mest tilsyneladende ubetydelige ændringer kunne føre til ret uforudsigelige effekter. Og netop sådanne komplekse beregningsprocesser, især dem der implementerer kritisk funktionalitet, er de bedste kandidater til automatisering. At kontrollere døre til døre tilfældene manuelt er meget tidskrævende. Da indgangspunktet til processen forbliver uændret, kan man ved én gang at beskrive det hurtigere masseproducere automatiserede tests og være sikker på funktionaliteten.
Da vores system aktivt anvendes, vil forretningen forvente noget nyt fra dig, at følge med tiden og være kundeorienteret. I vores loyalitetssystem frigives der nye versioner hver anden måned. Det betyder, at vi hvert andet måned skal udføre en fuld regression af hele systemet. Som i enhver moderne IT, går udviklingen naturligvis ikke direkte fra udvikler til produktion. Den begynder på udviklerkonturen, går derefter gennem testmiljøet, frigivelsesmiljøet, accepttestmiljøet, og endelig når den produktionen. I det mindste skal vi udføre en fuld regression af hele systemet på test- og frigivelsesmiljøerne.
De beskrevne egenskaber er standard for næsten ethvert loyalitetssystem. Lad os tale om særegenhederne ved vores projekt.
Teknologisk set er 90% af logikken i vores loyalitetssystem serverbaseret og implementeret i Oracle. Der er en klient til Delphi, der fungerer som administratorens arbejdsplads. Der er udsatte webtjenester til eksterne applikationer (for eksempel webstedet). Derfor er det ganske logisk, at hvis vi skal implementere et automatiseret testsystem, så vil vi gøre det på Oracle.
Loyalty system in Sportmaster has been around for over 7 years and was created by individual developers… The average number of developers on our project during these 7 years was 3-4 people. However, in the past year, our team has significantly increased, and now 10 people are working on the project. This means that new team members are coming on board who are not familiar with standard tasks, processes, and architecture. There is a heightened risk that we will overlook mistakes.
The project is characterized by the absence of dedicated testers as full-time staff. Certainly, testing is done, but it is conducted by analysts, in addition to their other key responsibilities: communicating with business clients, users, developing system requirements, etc. Despite the fact that testing is conducted very thoroughly (it is especially worth mentioning as some of the analysts might come across this report), the effectiveness of specialization and focus on a single task cannot be overlooked.
Given all of the above, to improve the quality of the delivered product and reduce development timelines, the idea of automating testing on the project seems quite logical. At different stages of the loyalty system's existence, individual developers have made efforts to cover their code with unit tests. This was generally a rather fragmented process, where each individual used their own architecture and methods. The common outcomes for unit tests were that tests were developed, used for some time, stored in version control, but at some point, they stopped running and were forgotten. This primarily happened because the tests were more tied to specific executors rather than the project.
Help comes from utPLSQL

Do you know anything about Steven Feurstain?
Han er en klog fyr, der har brugt en betydelig del af sin karriere på at arbejde med Oracle og PL/SQL, og han har skrevet en hel del om emnet. En af hans kendte bøger bærer titlen: «Oracle PL/SQL. For professionelle». Det var Stephen, der udviklede løsningen utPLSQL, som står for Unit Testing framework for Oracle PL/SQL. Løsningen utPLSQL blev skabt i 2016, men der arbejdes stadig aktivt på den, og der udgives nye versioner. På tidspunktet for foredraget var den nyeste version dateret 24. marts 2019.
Hvad er det egentlig? Det er et separat open source-projekt. Det fylder et par megabyte inklusive eksempler og dokumentation. Fysisk set er det en separat skema i ORACLE-databasen med et sæt pakker og tabeller til organisering af unit-testning. Installationen tager et par sekunder. En særpræg ved utPLSQL er enkelheden i brugen.
Overordnet set repræsenterer utPLSQL en mekanisme til at køre unit-tests, hvor en unit-test forstås som almindelige Oracle-pakkeprocedurer, hvis organisation følger visse regler. Udover at køre tests, gemmer utPLSQL en log over alle dine testkørsler, og der er også et internt rapporteringssystem.
Lad os se på et eksempel på, hvordan koden til en unit-test ser ud, når den er implementeret efter denne metode.

Så på skærmen vises koden til en typisk pakke-specifikation med unit-tests. Hvilke obligatoriske krav er der? Pakken skal have præfikset «utp_». Alle procedurer med tests skal have præcis det samme præfiks. I pakken skal der obligatorisk være to standardprocedurer: «utp_setup» og «utp_teardown». Den første procedure kaldes før hver unit-test, den anden kaldes efter kørslen.
«utp_setup» forbereder normalt vores system til at køre unit-testen, for eksempel ved at oprette testdata. «utp_teardown» - derimod - sørger for at returnere alt til de oprindelige indstillinger og nulstille resultaterne af kørslen.
Her er et eksempel på den mest grundlæggende unit test, der kontrollerer normaliseringen af det indtastede kundenummer til den standardform, vi har i vores loyalitetssystem. Der er ingen obligatoriske standarder for, hvordan man skriver procedurer med unit tests. Som regel kaldes en eller anden metode i det testede system, og det resultat, som denne metode returnerer, sammenlignes med et referenceværdi. Det er vigtigt, at sammenligningen mellem referenceværdien og den opnåede foregår gennem standard utPLSQL-metoder.
Der kan være et vilkårligt antal kontroller i unit testen. Som det fremgår af eksemplet, foretager vi fire på hinanden følgende opkald til den testede metode for normalisering af telefonnummeret, og efter hvert opkald vurderer vi resultatet. Ved udviklingen af en unit test skal man tage højde for, at der findes kontroller, der ikke påvirker systemet, mens der efter nogle skal rulles tilbage til systemets oprindelige tilstand.
For eksempel i den præsenterede unit test formaterer vi blot det indkommende telefonnummer, hvilket ikke har nogen indvirkning på loyalitetssystemet.
Men når vi skriver unit tests for metoden til oprettelse af en ny klient, vil der efter hver test blive oprettet en ny klient i systemet, hvilket kan påvirke den efterfølgende kørsel af testen.

Sådan køres unit tests. Der er to tilladte måder at køre dem på: at køre alle unit tests fra en bestemt pakke eller at køre en specifik unit test i en bestemt pakke.

Her er et eksempel på et internt rapportsystem. På baggrund af resultaterne af unit testen genererer utPLSQL en lille rapport. Her ser vi resultatet af hver specifik kontrol samt det samlede resultat af unit testen.
6 regler for automatiserede tests
Før vi går i gang med at opbygge et nyt system til automatiseret testning af loyalitetssystemet, har vi i samarbejde med ledelsen fastlagt de principper, som vores fremtidige automatiserede tests skal overholde.

- Automatiserede tests skal være effektive og gøre gavn. Vi har fantastiske udviklere, som absolut fortjener at blive nævnt, for en af dem vil sandsynligvis se denne rapport, og de skriver strålende kode. Men selv deres fantastiske kode er ikke perfekt og har, har stadig og vil altid have fejl. Automatiserede tests skal finde disse fejl. Hvis ikke, så skriver vi enten dårlige automatiserede tests, eller vi er kommet ind i et dødvande, som i princippet ikke udvikles. I begge tilfælde gør vi noget forkert, og vores tilgang er simpelthen meningsløs.
- Automatiserede tests skal bruges. Det er meningsløst at bruge en masse tid og kræfter på at skrive et softwareprodukt, pakke det i et repository og så glemme det. Tests skal køres, og de skal køres så regelmæssigt som muligt.
- Automatiserede tests skal arbejde stabilt. Uanset tid på dagen, teststand og andre systemindstillinger skal testresultaterne være de samme. Som regel sikres dette ved, at automatiserede tests arbejder med særlige testdata med faste systemindstillinger.
- Automatiserede tests skal køre med en hastighed, der er acceptabel for dit projekt. Denne tid bestemmes individuelt for hvert system. Nogle kan tillade at arbejde hele dagen, mens andre kritisch skal klare det inden for sekunder. Hvilke hastighedsnormer vi har opnået i vores projekt, vil jeg fortælle mere om senere.
- Udviklingen af automatiserede tests skal være fleksibel. Det er uønsket at opgive at teste en funktionalitet bare fordi vi ikke har gjort det før eller af andre ideologiske grunde. utPLSQL pålægger ingen begrænsninger for udviklingen, og Oracle tillader generelt at implementere meget forskellige ting. De fleste opgaver har en løsning; spørgsmålet er kun om tid og de ressourcer, der er brugt.
- Udrulning. Vi har flere teststande, hvor tests skal køres. På hver af standene kan data-dumpet opdateres når som helst. Projektet med automatiserede tests skal styres således, at det er muligt at udføre en fuld eller delvis installation uden problemer.
Og i det andet indlæg om et par dage vil jeg fortælle, hvad vi har gjort, og hvilke resultater vi har opnået.
Kilde: habr.com
