-
Notifications
You must be signed in to change notification settings - Fork 67
laskari 4
- palautusta varten tarvitaan yksityinen repositorio, jolla collaboratorina käyttäjä mluukkai
- kannattaa käyttää samaa repoa kuin esim. viikon 2 tehtävissä
- palautusrepositorion nimi ilmoitetaan tehtävien lopussa olevalla palautuslomakkeella
Maven-projekti konfiguroidaan projektin juuressa olevassa pom.xml-tiedostossa.
Tutkitaan hieman viime viikon tehtävissä 3-5 käytetyn projektin eli repositorion https://github.com/mluukkai/ohtu2016 hakemistossa viikko4/LoginWeb2 olevan projektin pom.xml:in sisältöä.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>LoginEasyBv1</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>LoginEasyBv1</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<easyb.version>1.5</easyb.version>
<cobertura.version>2.4</cobertura.version>
<org.springframework.version>3.1.1.RELEASE</org.springframework.version>
</properties>
<dependencies>
<!-- testing -->
<dependency>
<groupId>org.easyb</groupId>
<artifactId>easyb-core</artifactId>
<version>${easyb.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit-dep</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<!-- SPRING -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${org.springframework.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura.version}</version>
<configuration>
<formats>
<format>html</format>
<format>xml</format>
</formats>
</configuration>
</plugin>
<plugin>
<groupId>org.easyb</groupId>
<artifactId>maven-easyb-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
<configuration>
<storyType>html</storyType>
<storyReport>${basedir}/target/easyb/easyb-report.html
</storyReport>
</configuration>
</plugin>
</plugins>
</build>
</project>
Alussa määritellään projektin tiedot (nimi, versio.)
Kohdassa properties määritellään mm. alempana käytettäviä vakioita
Maven osaa ladata riippuvuuksia (eli käytännössä jar-tiedostoja) automaattisesti oletusrepositorioista. Kaikki riippuvuudet eivät kuitenkaan löydy oletusrepositorioista ja tälläisiä tilanteita varten osaan repositories voi määritellä vaihtoehtoisia repositorioita joista maven voi etsiä riippuvuuksia.
Riippuvuudet määritellään osassa dependencies
- alussa olevien riippuvuuksien (mm. easyb, junit) scope on test, tämä tarkoittaa että ne ovat käytössä vain testeissä
- selenium-riippuvuuden scope on compile, tällöin selenium on käytössä testeissä ja normaalissa koodissa
- jos ohjelmassa tarvitaan jar:eja, tulee niitä vastaavat maven-riippuvuudet kirjata dependencies-osaan, riippuvuuksia voi etsiä mm. seuraavista: http://search.maven.org tai http://mvnrepository.com/
Osassa build määritellään kääntämiseen liittyvien pluginien toimintaa
- kääntämisessä määritellään käytettävän javan versiota 1.6, tämä tapahtuu maven-compiler-plugin:ia konfiguroimalla
- jos tätä konfiguraatiota ei tehdä käyttää compiler-plugin oletusarvoista javan versiota. maven 3:ssa se on 1.6 mutta maven 2.*:ssa versio 1.3
- seuraavaksi määritellään, että cobertura-plugin tuottaa raporttinsa html:nä ja xml:nä
- jetty-pluginiin liittyy enemmänkin konfiguraatioita
- kohdan executions-alla määritellään, että jetty (eli sovelluksen käyttämä maven-projektiin integroitu web-palvelin) käynnistetään vaiheessa pre-integration-test ja sammutetaan vaiheessa post-integration-test, tämä saa aikaan sen, että kun ajetaan integraatiotestejä, eli suoritetaan komento
mvn integration-test
, on jetty päällä testien ajamisen aikana
- kohdan executions-alla määritellään, että jetty (eli sovelluksen käyttämä maven-projektiin integroitu web-palvelin) käynnistetään vaiheessa pre-integration-test ja sammutetaan vaiheessa post-integration-test, tämä saa aikaan sen, että kun ajetaan integraatiotestejä, eli suoritetaan komento
- easyb-pluginin määritellään ajavan testit integration-test-vaiheessa
Hae repositorion https://github.com/mluukkai/ohtu2016 hakemistossa viikko4/TyhjaProjekti lähes tyhjän maven-projektin runko.
- mukana on kohta tarvitsemasi luokka Submission
Tehdään ohjelma jonka avulla voit lukea kurssilla palauttamiesi tehtävien statistiikan osoitteesta http://ohtustats2016.herokuapp.com/
Omat palautukset palauttava sivu on http://ohtustats2016.herokuapp.com/students/012345678/submissions (vaihda 012345678 omaksi opiskelijanumeroksesi). Palvelin palauttaa tietosi json-muodossa
Tavoitteena on tehdä ohjelma, joka ottaa komentoriviparametrina opiskelijanumeron ja tulostaa palautettujen tehtävien statistiikan ihmisystävällisessä muodossa.
Ohjelmassa tarvitaan muutamaa kirjastoa:
- HTTP-pyynnön tekemiseen http://hc.apache.org/httpcomponents-client-4.4.x/
- InputStreamin merkkijonoksi muuttamiseen http://commons.apache.org/io/
- json-muotoisen merkkijonon muuttaminen olioksi http://code.google.com/p/google-gson/
Liitä projektisi pom.xml:n seuraavat riippuvuudet
- commons-httpclient, Commons IO, gson
- löydät riippuvuuksien tiedot osoitteesta http://mvnrepository.com/
- Ainakin seuraavat versiot on todettu yhteensopiviksi ja toimivaksi projektin koodin kanssa: commons-httpclient 3.1, Commons IO 2.0, gson 2.1
Ota mallia edellisen tehtävän projektista ja määrittele maven-compiler-plugin käyttämään javan versiota 1.6
Voit ottaa projektisi pohjaksi seuraavan tiedoston:
import com.google.gson.Gson;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.io.IOUtils;
public class Main {
public static void main(String[] args) throws IOException {
String studentNr = "012345678";
if ( args.length>0) {
studentNr = args[0];
}
String url = "http://ohtustats2016.herokuapp.com/students/"+studentNr+"/submissions";
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(url);
client.executeMethod(method);
InputStream stream = method.getResponseBodyAsStream();
String bodyText = IOUtils.toString(stream);
System.out.println("json-muotoinen data:");
System.out.println( bodyText );
Gson mapper = new Gson();
Submission[] subs = mapper.fromJson(bodyText, Submission[].class);
System.out.println("Oliot:");
for (Submission submission : subs) {
System.out.println(submission);
}
}
}
HUOM: jos teet koodia NetBeansilla, kirjastoja ei ehkä tunnisteta ennenkiun teet clean and buildin ja NB lataa ne mavenin repositoriosta koneellesi.
Tehtäväpohjassa on valmiina luokan Submission
koodin runko. Gson-kirjaston avulla json-muotoisesta datasta saadaan taulukollinen Submission
-olioita, joissa jokainen olio vastaa yhden viikon palautusta. Tee luokkaan oliomuuttuja (sekä tarvittaessa getteri ja setteri) jokaiselle json-datassa olevalle kentälle, jota ohjelmasi tarvitsee. Kentät a1, a2 jne vastaavat viikolla tehtyjä yksittäisiä tehtäviä.
Tee kuitenkin ohjelmastasi tulostusasultaan miellyttävämpi, esim. seuraavaan tyyliin:
opiskelijanumero 012345678 viikko 1: tehtyjä tehtäviä yhteensä: 9, aikaa kului 3 tuntia, tehdyt tehtävät: 1 2 3 4 5 6 7 9 11 viikko 2: tehtyjä tehtäviä yhteensä: 6, aikaa kului 4 tuntia, tehdyt tehtävät: 1 2 3 6 7 8 yhteensä: 15 tehtävää 7 tuntia
- tehdään äskeisen tehtävän projektista jar-tiedosto komennolla
mvn install
- suoritetaan ohjelma komennolla
java -cp tiedostonNimi.jar ohtu.Main
- mutta ohjelma ei toimikaan, tulostuu:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/httpclient/HttpMethod
Caused by: java.lang.ClassNotFoundException: org.apache.commons.httpclient.HttpMethod
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Could not find the main class: ohtu.Main. Program will exit.
Mistä on kyse?
- ohjelman riippuvuuksia eli projekteja commons-httpclient, Commons IO ja gson vastaavat jar-tiedostot eivät ole käytettävissä, joten ohjelma ei toimi
- saamme generoitua ohjelmasta jar-tiedoston joka sisältää myös riippuvuudet mavenin assembly-pluginin avulla
- lisää pom.xml:n plugineihin seuraava:
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
komennolla mvn assembly:assembly
syntyy koko ohjelman sisältävä "standalone"-jar-tiedosto:
$ java -cp TyhjaProjekti2-1.0-jar-with-dependencies.jar ohtu.Main 012345678 opiskelijanumero 012345678 viikko 1: tehtyjä tehtäviä yhteensä: 9, aikaa kului 3 tuntia, tehdyt tehtävät: 1 2 3 4 5 6 7 9 11 viikko 2: tehtyjä tehtäviä yhteensä: 6, aikaa kului 4 tuntia, tehdyt tehtävät: 1 2 3 6 7 8 yhteensä: 15 tehtävää 7 tuntia
Riippuvuudet sisältävä jar-voidaan myös tehdä käyttämällä mavenin shade-pluginia Shade-pluginin avulla saadaan itseasiassa aikaan "helppokäyttöisempi" jar, joka voidaan käynnistää määrittelemättä main-metodin sisältävää luokkaa.
Määrittele shade-pluginille mainClassin sijainti lisäämällä pom.xml:ääsi seuraava:
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>ohtu.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Saat luotua jar:in komennolla mvn package
, ja ohjelman suoritus tapahtuu komennolla java -jar tiedostonnimi.jar
Tee tämä tehtävä repositorioon, jonka palautat
- Lue http://git-scm.com/book/en/Git-Basics-Tagging (kohdat signed tags ja verifying tags voit skipata)
- tee tägi nimellä tagi1 (lightweight tag riittää)
- tee kolme committia (eli 3 kertaa muutos+add+commit )
- tee tägi nimellä tagi2
- katso
gitk
-komennolla miltä historiasi näyttää - palaa tagi1:n aikaan, eli anna komento
git checkout tagi1
- varmista, että tagin jälkeisiä muutoksia ei näy
- kokeile komentoa
git status
, mitä erikoista huomaat!
- palaa nykyaikaan
- tämä onnistuu komennolla
git checkout master
- tämä onnistuu komennolla
- lisää tägi edelliseen committiin
- onnistuu komennolla
git tag tagi1b HEAD^
, eli HEAD^ viittaa nykyistä "headia" eli olinpaikkaa historiassa edelliseen committiin - joissain windowseissa muoto
HEAD^
ei toimi, sen sijasta voit käyttää muotoaHEAD~
- tai katsomalla commitin tunniste (pitkä numerosarja) joko komennolla
git log
tai gitk:lla
- onnistuu komennolla
- kokeile molempia tapoja, tee niiden avulla kahteen edelliseen committiin tagit (tagi1a ja tagi1b)
- katso komennolla
gitk
miltä historia näyttää
Tagit eivät mene automaattisesti etärepositorioihin. Pushaa koodisi githubiin siten, että myös tagit siirtyvät mukana. Katso ohje täältä
Varmista, etä tagit siirtyvät Githubiin:
Tarkastellaan edelliseltä viikolta tutun toiminnallisuuden tarjoamaa esimerkkiprojektia joka löytyy repositorion https://github.com/mluukkai/ohtu2016 hakemistossa viikko4/LoginWeb2
Hae projekti ja käynnistä se komennolla
mvn jetty:run
Jetty on keyvt HTTP-palvelin ja Servlettien ajoympäristö. Projektiin on konfiguroitu Jetty Maven-pluginiksi. Jos kaikki menee hyvin, on sovellus nyt käynnissä ja voit käyttää sitä web-selaimella osoitteesta http://localhost:8090 eli paikalliselta koneeltasi portista 8090.
Jos koneellasi on jo jotain muuta portissa 8090, voit konfiguroida sovelluksen käynnistymään johonkin muuhun porttiin esim. 9999:n seuraavasti:
mvn -D jetty.port=9999 jetty:run
SpringWebMVC:stä tällä kurssilla ei tarvitse ymmärtää. Kannattaa kuitenkin vilkaista tiedostoa ohtu.OhtuController.java, joka sisältää sovelluksen eri osoitteisiin tulevista kutsuista huolehtivan koodin. Kontrolleri käyttää AuthenticationService-luokkaa toteuttamaan kirjautumisen tarkastuksen ja uusien käyttäjien luomisen. Kontrolleri delegoi www-sivujen renderöinnin hakemiston WebPages/WEB-INF-views alla oleville jsp-tiedostoille.
Eli tutustu nyt sovelluksen rakenteeseen ja toiminnallisuuteen. Saat sammutettua sovelluksen painamalla konsolissa ctrl+c tai ctrl+d.
Web-selaimen simulointi onnistuu mukavasti Selenium WebDriver -kirjaston avulla. Edellisessä tehtävässä olevassa projektissa on luokassa ohtu.Tester.java pääohjelma, jonka koodi on seuraava:
public static void main(String[] args) {
WebDriver driver = new HtmlUnitDriver();
driver.get("http://localhost:8090");
System.out.println( driver.getPageSource() );
WebElement element = driver.findElement(By.linkText("login"));
element.click();
System.out.println("==");
System.out.println( driver.getPageSource() );
element = driver.findElement(By.name("username"));
element.sendKeys("pekka");
element = driver.findElement(By.name("password"));
element.sendKeys("akkep");
element = driver.findElement(By.name("login"));
element.submit();
System.out.println("==");
System.out.println( driver.getPageSource() );
}
Käynnistä sovellus edellisen tehtävän tapaan komentoriviltä. Varmista selaimella että sovellus on päällä.
Aja Tester.java:ssa oleva ohjelma. Esim. NetBeansilla tämä onnistuu valitsemalla tiedoston nimen kohdalta oikealla hiiren napilla "Run file".
Katso mitä ohjelma tulostaa.
Tester-ohjelmassa luodaan alussa selainta simuloiva olio WebDriver driver. Tämän jälkeen "mennään" selaimella osoitteeseen localhost:8090 ja tulostetaan sivun lähdekoodi. Tämän jälkeen haetaan sivulta elementti, jossa on linkkiteksti login eli
WebElement element = driver.findElement(By.linkText("login"));
Linkkielementtiä klikataan ja jälleen tulostetaan sivun lähdekoodi. Seuraavaksi etsitään sivulta elementti, jonka nimi on username, kyseessä on lomakkeen input-kenttä, ja ohjelma "kirjoittaa" kenttään komennolla sendKeys() nimen "pekka".
Tämän jälkeen täytetään vielä salasanakenttä ja painetaan lomakkeessa olevaa nappia. Lopuksi tulostetaan vielä sivun lähdekoodi.
Ohjelma siis simuloi selaimen käyttöskenaarion, jossa kirjaudutaan sovellukseen.
Muuta koodia siten, että läpikäyt seuraavat skenaariot:
- epäonnistunut kirjautuminen: oikea käyttäjätunnus, väärä salasana
- epäonnistunut kirjautuminen: ei-olemassaoleva käyttäjätunnus
- uuden käyttäjätunnuksen luominen
- uuden käyttäjätunnuksen luomisen jälkeen tapahtuva ulkoskirjautuminen sovelluksesta
HUOM: salasanan varmistuskentän (confirm password) nimi on passwordConfirmation
Pääsemme jälleen käyttämään viime viikolta tuttua easyB:tä. Hakemistosta Other Test Sources/easyb löytyy valmiina User storyn User can log in with valid username/password-combination määrittelevä story. Yksi skenaarioista on valmiiksi mäpätty koodiin. Täydennä kaksi muuta skenaariota.
Kuten viime viikolta muistamme, toinen järjestelmän toimintaa määrittelevä User story on A new user account can be created if a proper unused username and a proper password are given
Löydät tämän Storyn easyB-pohjan viime viikon tehtävistä. Kopioi story projektiisi ja tee skenaarioista suoritettavia kirjoittamalla niihin Seleniumin avulla (edellisen tehtävän tyyliin) sovellusta testaavaa koodia. Muista lisätä story-tiedostoon Seleniumin vaatimat importit!
Huomioita
- voit tehdä Tester.java:n tapaisen pääohjelman sisältävän luokan jos haluat/joudut debuggaamaan testiä.
- Uuden käyttäjän luomisen pohjalla käytettävään luokkaan UserData on määritelty validoinnit käyttäjätunnuksen muodon ja salasanan oikeellisuuden tarkastamiseksi. Eli toisin kuin viime viikolla, ei AuthenticationServicen tarvitse suorittaa validointeja.
- Skenaarion "can login with succesfully generated account" mäppäävän koodin kirjoittaminen ei ole täysin suoraviivaista. Koska luotu käyttäjä kirjautuu automaattisesti järjestelmään, joudut kirjaamaan käyttäjän ensin ulos ja kokeilemaan tämän jälkeen että luotu käyttäjä pystyy kirjautumaan sivulle uudelleen.
- Huomaa, että jos luot käyttäjän yhdessä testissä, et voi luoda toisessa testissä samannimistä käyttäjää uudelleen!
tehtävien kirjaus:
- Kirjaa tekemäsi tehtävät tänne
- huom: tehtävien palautuksen deadline on su 17.4. klo 23.59
palaute tehtävistä:
- Lisää viikon 1 tehtävässä 11 forkaamasi repositorion omalla nimelläsi olevaan hakemistoon tiedosto nimeltä viikko4
- tee viime viikon tehtävän tapaan pull-request
- anna tehtävistä palautetta avautuvaan lomakkeeseen
- huom: jos teet tehtävät alkuviikosta, voi olla, että edellistä pull-requestiasi ei ole vielä ehditty hyväksyä ja et pääse vielä tekemään uutta requestia