-
Notifications
You must be signed in to change notification settings - Fork 67
lh4 2017 draft
Tehtävien palautuksen deadline su 9.4. klo 23.59 ohjausta tehtävien tekoon to 12-14 ja pe 14-16 salissa B221
- palautusta varten voit käyttää samaa repoa kuin aiemman viikon palautuksissasi
- palautusrepositorion nimi ilmoitetaan tehtävien lopussa olevalla palautuslomakkeella
Hae kurssirepositorion https://github.com/mluukkai/ohtu2017 hakemistossa [https://github.com/mluukkai/ohtu2017](https://github.com/mluukkai/ohtu2017/koodi/viikko4/TyhjaProjekti](viikko4/TyhjaProjekti) lähes tyhjä gradle-projektin runko.
- mukana on kohta tarvitsemasi luokka Submission
Tehdään ohjelma jonka avulla voit lukea kurssilla palauttamiesi tehtävien statistiikan osoitteesta http://ohtustats2017.herokuapp.com/
Omat palautukset palauttava sivu on http://ohtustats2017.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
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://ohtustats2017.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 ennenkuin teet trick
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
Tehtävässä oletetaan, että sinulla on 2 repositoria GitHub:issa. Käytetään niistä nimiä A ja B
- kloonaa A koneellesi
- liitä B paikalliselle koneelle kloonaamaasi repositorioon etärepositorioksi
- nyt paikallisella repositoriollasi on kaksi remotea A (nimellä origin) ja B (määrittelemälläsi nimellä)
- tarkista komennolla git remote -v että näin todellakin on
- pullaa B:n master-haaran sisältö paikalliseen repositorioon (komennolla
git pull beelleantamasinimi master
)- pullaus siis aiheuttaa sen, että etärepositorin master-haara mergetään lokaalin repositorion masteriin, tämä voi aiheuttaa konfliktin, jos, niin ratkaise konflikti!
- pushaa paikallisen repositorion sisältö A:han eli originiin
jatketaan edellistä
- liitä paikalliseen repositorioosi (edellisen tehtävän A) remoteksi repositorio
git://github.com/mluukkai/ohtu2017.git
esim. nimellä ohtu - ei pullata ohtu-repossa olevaa tavaraa lokaaliin, vaan tehdään sille oma träkkäävä branchi:
- anna komennot
git fetch ohtu
jagit checkout -b ohtu-lokaali ohtu/master
- varmista komennolla
git branch
että branchi (nimeltä ohtu-lokaali) syntyi ja että olet branchissa - tee komento
ls
niin näet, että olet todellakin ohtu-repon lokaalissa kopiossa
- anna komennot
- siirretään (tai otetaan mukaan, alkuperäinen ei häviä) ohtu-lokaali:n hakemisto viikko2 paikallisen repon masteriin:
- palaa master-branchiin komennolla
git checkout master
- liitä branchin ohtu-lokaali hakemisto viikko2 masteriin komennolla
git checkout ohtu-lokaali viikko2
- varmista että hakemisto on nyt staging-alueella komennolla
git status
- committaa
- nyt sait siirrettyä sopivan osan toisen etärepositorion tavarasta lokaaliin repositorioon!
- palaa master-branchiin komennolla
- pushaa lokaalin repositorion sisältö sekä originiin että B:hen
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
- 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:
HUOM: tarvitset tässä tehtävässä mavenista version 3, ohjelma ei toimi versiolla 2. Kun asennat uuden version poista vanhan version koneellesi lataamat riippuvuudet poistamalla kotihakemistossasi oleva hakemisto .m2
Tarkastellaan edelliseltä viikolta tutun toiminnallisuuden tarjoamaa esimerkkiprojektia joka löytyy repositorion https://github.com/mluukkai/ohtu2017 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.
Jos koneessasi on Firefox, muuta Testerin pääohjelman rivi 11 muotoon:
WebDriver driver = new FirefoxDriver();
Suorita tester uudelleen. Jos koneesi Firefox-versio on yhteensopiva käytössä olevan selenium-version kanssa, sinun pitäisi nähdä Firefoxin käynnistyvän ja seleniumin "suorittavan" koodin skenaario Firefoxilla.
Muuta nyt koodia siten, että läpikäyt seuraavat skenaariot (jos FirefoxFriver ei toimi koneellasi, käytä alunperin koodissa käytettyä HtmlUnitDriver
:ia):
- 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.
Testit on konfiguroitu suoritettavaksi samalla tavalla kuin viime viikon easyB-tehtävässä. Huomaa, että voit testeissäkin halutessasi käyttää FirefoxDriver
:ia.
Huom: Firefox ei jostain syystä toimi easyB:n kanssa jos testejä suoritetaan Travisissa. Jos joudut esim. miniprojektissa käyttämään FirefoxDriveria, joudut Travisin takia toteuttamaan testit jUnitilla.
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ä. Toinen hyvä debuggaustapa on FirefoxDriverin käyttö
- 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 9.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