Testirajte web aplikacije s HttpUnit-om

U tipičnoj poslovnoj aplikaciji mnoga područja zahtijevaju testiranje. Polazeći od najjednostavnijih komponenata, klasa, programeri ili programeri specijaliziranih testova moraju programirati jedinične testove kako bi osigurali da se najmanje jedinice aplikacije ponašaju ispravno. Svaka komponenta potencijalno može sama proći jedinstvene testove; međutim programeri moraju osigurati suradnju prema očekivanjima - kao dio podsustava i kao dio cijele aplikacije - stoga se moraju provesti integracijski testovi . U nekim projektima moraju se ispuniti zahtjevi za izvedbu, tako da inženjeri osiguranja kvalitete provode ispitivanja opterećenja kako bi provjerili i dokumentirali učinak aplikacije pod različitim uvjetima. Tijekom razvoja aplikacija, inženjeri osiguranja kvalitete provode automatizirana i ručna ispitivanja funkcionalnostiza testiranje ponašanja aplikacije s gledišta korisnika. Kada razvojni projekt gotovo ispuni određenu prekretnicu, mogu se provesti testovi prihvaćanja kako bi se potvrdilo da je aplikacija ispunjavala zahtjeve.

HttpUnit je okvir zasnovan na JUnit-u, koji omogućuje implementaciju automatiziranih testnih skripti za web aplikacije. Najprikladniji je za provedbu automatiziranih funkcionalnih testova ili testova prihvaćanja. Kao što naziv sugerira, može se koristiti za jedinstveno testiranje; međutim, tipične komponente web sloja kao što su JSP (JavaServer Pages) stranice, servleti i druge komponente predloška ne podliježu jedinstvenom testiranju. Što se tiče različitih komponenata temeljenih na MVC (Model-View Controller), one su prikladnije za testiranje s drugim okvirima za testiranje. Akcije strutova mogu se jedinstveno testirati pomoću StrutsUnit, a akcije WebWork 2 mogu se jedinstveno testirati bez web-spremnika, na primjer.

Ispitni ciljevi

Prije nego što uskočimo u detalje o arhitekturi i implementaciji, važno je razjasniti što će test skripte trebati dokazati o web aplikaciji. Moguće je jednostavno simulirati ponašanje slučajnog posjetitelja web stranice jednostavnim klikom na zanimljive poveznice i čitanjem stranica slučajnim redoslijedom, ali rezultat tih slučajnih skripti ne bi opisao cjelovitost i kvalitetu aplikacije.

Tipična poslovna web aplikacija (ili složena web stranica) ima nekoliko dokumenata koji opisuju zahtjeve različitih korisnika ili održavatelja aplikacija. To može uključivati ​​specifikacije slučaja upotrebe, specifikacije nefunkcionalnih zahtjeva, specifikacije testnog slučaja izvedene iz ostalih artefakata, dokumente o dizajnu korisničkog sučelja, makete, profile glumaca i razne dodatne artefakte. Za jednostavnu aplikaciju, cijela bi se specifikacija mogla sastojati od jednostavne tekstualne datoteke s popisom zahtjeva.

Iz tih dokumenata moramo stvoriti organizirani popis testnih slučajeva. Svaki testni slučaj opisuje scenarij koji web posjetitelj može ostvariti putem web preglednika. Dobra je praksa ciljati na scenarije slične veličine - veći scenariji mogu se raščlaniti na manje dijelove. Mnogo izvrsnih knjiga i članaka raspravlja o stvaranju specifikacija test slučajeva. U ovom članku pretpostavimo da imate skup stavki koje želite testirati za svoju web aplikaciju, organizirane u skupove scenarija testnih slučajeva.

Vrijeme je za preuzimanje stvari!

Dobro, sad znamo dosadne stvari, hajde da preuzmemo neke super igračke! Prije svega, potreban nam je instalirani Java 2 SDK za kompajliranje i izvršavanje naših testova. Zatim moramo preuzeti HttpUnit framework - trenutno u verziji 1.5.5. Binarni paket sadrži sve potrebne biblioteke trećih strana. Trebat će nam i alat za izradu mrava za pokretanje testova i automatsko generiranje izvješća. Svaka prilično novija verzija ovih alata vjerojatno bi funkcionirala; Jednostavno više volim koristiti najnoviju i najbolju verziju svega.

Da biste napisali i izvršili testove, preporučujem upotrebu IDE-a koji ima ugrađeni pokretač JUnit testa. Koristim Eclipse 3.0M7 za razvijanje testnih skripti, ali IntelliJ također ima podršku za JUnit, kao i nedavno objavljeni IDE-i.

HttpUnit: HTTP simulator klijenta

Budući da želimo testirati web aplikacije, idealno bi bilo da se alat za testiranje ponaša točno kao korisnički web preglednici. Naša aplikacija (ispitni cilj) ne bi trebala biti svjesna bilo kakve razlike prilikom posluživanja stranica web pregledniku ili testnom alatu. Upravo to pruža HttpUnit: simulira GET i POST zahtjeve uobičajenog preglednika i pruža lijep objektni model pomoću kojeg se mogu kodirati naši testovi.

Pogledajte detaljan vodič za API za ostale razrede i metode; Slika 1 daje samo kratki pregled predavanja koje najčešće koristim. Korisnička sesija (slijed interakcija s web aplikacijom) enkapsulirana je s WebConversation. Konstruiramo WebRequests, obično konfigurirajući URL i parametre, a zatim ih šaljemo niz WebConversation. Zatim okvir vraća a WebResponse, koji sadrži vraćenu stranicu i atribute s poslužitelja.

Evo primjera testnog slučaja HttpUnit iz dokumenata HttpUnit:

/ ** * Potvrđuje da podnošenje obrasca za prijavu s imenom "master" rezultira * na stranici koja sadrži tekst "Top Secret" ** / public void testGoodLogin () baca izuzetak {WebConversation razgovor = new WebConversation (); Zahtjev za WebRequest = novi GetMethodWebRequest ("//www.meterware.com/servlet/TopSecret"); WebResponse odgovor = razgovor.getResponse (zahtjev); WebForm loginForm = response.getForms () [0]; request = loginForm.getRequest (); request.setParameter ("name", "master"); odgovor = razgovor.getResponse (zahtjev); assertTrue ("Prijava nije prihvaćena", response.getText (). indexOf ("Uspjeli ste!")! = -1); assertEquals ("Naslov stranice", "Strogo tajno", response.getTitle ()); }

Arhitektonska razmatranja

Primijetite kako gornji uzorak Java sadrži ime domene poslužitelja koji izvodi aplikaciju. Tijekom razvoja novog sustava, aplikacija živi na više poslužitelja i poslužitelji mogu pokretati više verzija. Očito je loša ideja zadržati ime poslužitelja u implementaciji Jave - za svaki novi poslužitelj moramo prekompajlirati svoje izvore. Ostale stavke ne bi trebale živjeti u izvornim datotekama, poput korisničkih imena i lozinki, koje bi trebale biti konfigurirane za određenu implementaciju. S druge strane, ne bismo trebali previše dizajnirati jednostavnu primjenu testnog slučaja. Specifikacija test slučaja obično sadrži većinu opisa stanja sustava i specifične opise parametara za naš scenarij, tako da nema smisla sve parameterizirati u implementaciji.

Tijekom kodiranja shvatit ćete da se mnogi odjeljci koda pojavljuju u više od jedne implementacije test-slučaja (potencijalno u svim testnim slučajevima). Ako ste iskusni objektno orijentirani programer, u iskušenju ćete stvoriti hijerarhiju klasa i uobičajene klase. U nekim slučajevima to ima puno smisla - na primjer, postupak prijave trebao bi biti uobičajena metoda dostupna za sve testne slučajeve. Međutim, morate se malo odmaknuti i shvatiti da ne gradite novi proizvodni sustav povrh aplikacije za testiranje - ove Java klase nisu ništa više od testnih skripti za provjeru rezultata web mjesta. Vježbajte zdrav razum i težite jednostavnim, sekvencijalnim i samostalnim test skriptama.

Test slučajevi su obično krhki. Ako programer promijeni URL, reorganizira izgled

will simple, sequential script

Traceability is crucial for our test cases. If something goes KA-BOOM, or, for example, a calculation result is wrong, it's important to point the developer to the corresponding test-case specification and the use-case specification for a quick bug resolution. Therefore, annotate your implementation with references to the original specification documents. Including the version number of those documents is also useful. That could be just a simple code comment or a complex mechanism where the test reports themselves link to the documents; the important thing is to have the reference in the code and to keep the traceability.

When do I get to write code?

Now that you're aware of the requirements (use-case docs and corresponding test-case specifications), understand the framework's basics, and have a set of architectural guidelines, let's get to work.

For the development of the test-case implementations, I prefer to work in Eclipse. First of all, it has a nice JUnit test runner. You can select a Java class, and from the Run menu, you can run it as a JUnit unit test. The runner displays the list of recognized test methods and the execution result. When everything goes okay during the test run, it gives a nice green line. If an exception or assertion failure occurred, it displays a distressing red line. I think the visual feedback is really important—it offers a sense of accomplishment, especially when writing unit tests for your own code. I also like to use Eclipse for its refactoring capabilities. If I realize that within a test-case class I need to copy and paste code sections, I can just use the Refactoring menu to create a method from the code section instead. If I realize that numerous test cases will use the same method, I can use the menu to pull up my method into my base class.

Based on the architectural requirements above, for each project, I typically create a base test-case class, which extends the JUnit TestCase class. I call it ConfigurableTestCase. Each test-case implementation extends this class, see Figure 2.

ConfigurableTestCase typically contains the common methods and initialization code for the test case. I use a property file to store the server name, the application context, various login names for each role, and some additional settings.

The specific test-case implementations contain one test method per test-case scenario (from the test-case specification document). Each method typically logs in with a specific role and then executes the interaction with the Web application. Most test cases do not need a specific user to accomplish the activities; they typically require a user in a specific role, like Administrator, or Visitor, or Registered User. I always create a LoginMode enum, which contains the available roles. I use the Jakarta Commons ValuedEnum package to create enums for the roles. When a specific test method in a test-case implementation logs in, it must specify which login role is required for that particular test scenario. Of course, the ability to log in with a specific user should also be possible, for example, to verify the Registered User use case.

After each request and response cycle, we typically need to verify if the returned page contains an error, and we need to verify our assertions about what content the response should contain. We must be careful here as well; we should only verify items that are not variable and not too fragile in the application. For example, if we assert specific page titles, our tests will probably not run if the language is selectable in the application and we want to verify a different language deployment. Similarly, there's little point in checking an item on the page based on its position within a table layout; table-based designs change frequently, so we should strive to identify elements based on their IDs. In case some important elements on the page don't have IDs or names, we should just ask the developers to add them, rather than trying to work around them.

JUnit assertions offer a poor approach for checking if the look and feel, layout, and page design comply with the requirements. It is possible, given an infinite amount of time for the test development, but a good human tester can assess these things more efficiently. So concentrate on verifying the Web application's functionality, rather than checking everything possible on the page.

Here's an updated test scenario based on our test-case architecture. The class extends ConfigurableTestCase, and the login details are handled in the base class:

 /** * Verifies that submitting the login form with the name "master" results * in a page containing the text "Top Secret" **/ public void testGoodLogin() throws Exception { WebConversation conversation = new WebConversation(); WebResponse response = login(conversation, LoginMode.ADMIN_MODE); assertTrue( "Login not accepted", response.getText().indexOf( "You made it!" ) != -1 ); assertEquals( "Page title", "Top Secret", response.getTitle() ); } 

Tips and tricks

Most scenarios can be handled quite easily by setting WebForm parameters and then looking for specific elements with results in the WebResponse pages, but there are always some challenging test cases.





strukturu ili promijeni ID elementa obrasca, posjetitelj vjerojatno neće vidjeti nikakvu razliku, ali vaše testne skripte će biti puhane. Očekujte puno prerade i promjene za svaku provedbu testnog slučaja. Objektno orijentirani dizajn mogao bi smanjiti napor za preradom uobičajenih dijelova u testnim slučajevima, ali iz perspektive inženjera ili ispitivača osiguranja kvalitete, siguran sam da je interakciju s web stranicom lakše održavati i popravljati. #####