Programming Language Pragmatics

Download Report

Transcript Programming Language Pragmatics

582101 - Ohjelmistotekniikan menetelmät,
toteutuksesta ja testauksesta
1
Toteutuksesta ja testauksesta
•
•
•
•
•
Suunnitteluprosessista
Tarkan tason luokkasuunnittelu
Siirtyminen UML-kaavioista Java-toteutukseen
Yksikkötestaus ja testausohjattu kehitys (TDD)
Hyväksymis- ja regressiotestaus
2
Yleistä suunnitteluprosessista
Liiketoimintatason malli järjestelmän määrittelynä
Karkean tason
käyttötapaukset
Käyttöliittymäsuunnitelma
Liiketoimintaoliot
Kohdealuetason käsitteellinen malli
Tarkat
käyttötapaukset
Arkkitehtuurimalli
Analyysitason
luokkamalli
Suunnittelutason malli
Vuorovaikutuskaaviot
Tarkan suunnittelutason luokat
Tietokantamalli
3
Erilaisia suunnittelutason olioiden lähtökohtia
Käyttöliittymä- Arkkitehtuurisuunnitelma
malli
Tarkat
Analyysitason
käyttötapaukset luokkamalli
Tarkan
suunnittelutason
luokkamalli
Käyttöliittymäoliot (View)
Kontrollioliot
Sisältöoliot
(Controller)
(Model)
4
Käyttöliittymästä sisältöön
• Suunnittele käyttöliittymä ja valitse sovellettava
arkkitehtuurimalli, esim. MVC
• Sisällytä suunnitelmaasi tarvittavat
käyttöliittymäoliot ja luokat
• Sisällytä suunnitelmaasi kustakin käyttötapauksesta
vastaava kontrolliolio (sama voi vastata useasta)
• Määrittele kontrollioliolle käyttötapauksen
hoitamiseen tarvittavat operaatiot ja attribuutit
• Sisällytä suunnitelmaasi käyttötapauksessa
tarvittavat sisältöoliot (vrt. analyysitason
luokkamalli)
• Määrittele sisältöolioille käyttötapauksen hoitoon
tarvittavat operaatiot (lisää tarvittaessa luokkia)
5
Tarkan tason luokkasuunnittelu
• Tarkentaa alkuperäistä luokkamallia
• Syötteet (analyysitason luokkamallin lisäksi)
– käyttötapausmalli
• määrittelee toiminnallisuuden, joka on toteutettava
– valittu arkkitehtuurimalli (architectural framework)
• asettaa tiettyjä rajoitteita
• Tuottaa suunnittelutason luokat ja rajapinnat
yksityiskohtineen (erityisesti operaatiot)
• Etenee yleensä rinnakkain vuorovaikutussuunnittelun kanssa ja liittyy siihen kiinteästi
6
Palvelujen jakaminen luokkien operaatioiksi
• Lähtökohtana tietojärjestelmälle määritellyt palvelut
(käyttötapaukset)
• Palvelut toteutetaan olioiden yhteistyönä (olioiden
verkkona)
• Tavoitteena haluttujen palveluiden toteuttaminen
selkeän ja ylläpidettävän olioverkon avulla
• Oliolle (tai luokalle) voidaan antaa vastuu jostakin
palvelukokonaisuudesta ja operaatiot määräytyvät
tämän vastuun puitteissa
7
Palvelujen jakaminen luokkien operaatioiksi
• Palvelua määriteltäessä, on selvitettävä
– pystyykö luokan olio hoitamaan sen
itsenäisesti oman tietosisältönsä avulla;
ja ellei pysty
– millaista yhteistyötä muiden olioiden
kanssa tarvitaan
• Kumpikin selvityksistä voi tuottaa uusia
attribuutteja tai operaatioita
8
Esimerkki: Luokan KingKX125 operaatio
checkFrequency(double)
boolean checkFrequency(double frequency) {
// imaginary transmission test
if(Math.random() < 0.999999) {
return true;
}
return false;
}
• Itsenäinen, mutta ei kovinkaan älykäs
• Parempi toteutus voisi käyttää taajuuksia esittävää
oliota taajuuden testaamiseen
9
Esimerkki: Luokan KingKX125 operaatio
checkFrequency(double)
boolean checkFrequency(double freq) {
Frequency f;
f = FrequencyFactory.getFrequency(freq);
return f.transmissionTest();
}
• Toteuttaa palvelun toista oliota käyttäen
• Näin esiteltiin riippuvuus luokkaan Frequency; tuon
luokan toiminnan muuttuessa vaihtuu myös tämän
luokan toiminta
10
UML-kaaviosta toteutukseen
• UML-luokista puuttuu tyypillisesti yksityiskohtia,
jotka on kiinnitettävä luokan toteuttamiseksi
kooditasolla
• Olennaisinta on päättää yhteyksien toteuttamisesta
– 1-1-yhteydet toteutetaan tyypillisesti kohteen tyypin
mukaisina tietokenttinä (data member, data field)
– 1-N- ja N-M-yhteydet toteutetaan usein kokoelmaluokkien
avulla
• UML tarjoaa mahdollisuuden esittää luokat niin
tarkalla tasolla, että niistä voidaan generoida
luokkarungot
– metodien toteutuskoodia ei kuitenkaan yleensä anneta
– myöskään standardikirjastoihin kuuluvia kokoelma- ja
vastaavia luokkia ei yleensä merkitä näkyviin
11
Esimerkki: analyysitason käsitteellisestä
kaaviosta
listed_as
position
: double
movie
movie_code
movie_title
director
: double
: String
: String
actor
0..*
0..*
actor_code
actor_name
: double
: String
12
Esimerkki: .. suunnittelutason kaavioon
ListedAs
position : double
ListeAs contains:
actor: Actor
movie: Movie
Actor
actorCode : double
actorName : String
Actor()
addListedAs()
removeListedAs()
getActorCode()
setActorCode()
getActorName()
setActorName()
equals()
actor
ListedAs()
getPosition()
setPosition()
getMovie()
setMovie()
getActor()
setActor()
Movie
movieTitle : String
movie movieCode : double
director : String
1
Actor and Movie
contain:
listedAs: Collection
listedAs
0..1
listedAs
Collection
(from util)
0..1
1 Movie()
addListedAs()
removeListedAs()
getMovieTitle()
setMovieTitle()
getMovieCode()
setMovieCode()
getDirector()
setDirector()
equals()
13
Esimerkki: suunnittelutason luokasta ..
Movie
movieTitle : String
movieCode : double
director : String
Movie(movieCode : double, title : String, director : String)
addListedAs(l : ListedAs) : void
removeListedAs(l : ListedAs) : void
getMovieTitle() : String
setMovieTitle(title : String) : void
getMovieCode() : double
setMovieCode(code : double) : void
getDirector() : String
setDirector(dir : String) : void
equals(o : Object) : boolean
14
Esimerkki: .. vastaavaan Java-luokkaan
Movie.java
7: public class Movie {
8:
private String movieTitle;
9:
10:
private double movieCode;
11:
12:
private String director;
13:
14:
private Collection listedAs;
15:
16:
public Movie(double movieCode,String title,String
director){
17:
this.movieCode = movieCode;
18:
this.director = director;
19:
this.movieTitle = title;
20:
listedAs = new ArrayList();
21:
}
...
15
Testaus ohjelmistoprosessin eri vaiheissa
Käsitteellinen
luokkamalli
Käyttötapaukset
Luokkasuunnittelu
ja koodaus
Testausohjattu
ohjelmistokehitys
Muut spesifikaatiot
ja vaatimukset
Vikaraportit
Hyväksymistestaus
Arkkitehtuurimalli
Ylläpito ja
regressiotestaus
Päivityspyynnöt
16
Testaus ohjelmistoprosessin eri vaiheissa
(vaihtoehtoinen jaoittelu)
Reusable components
Programming
Design
specifications
Analysis
specifications
System
constraints
Customer
requirements
User
environment
Integration
test
Functional
test
Constraint
test
Acceptance
test
Installation
test
Unit
test
Unit
test
Performance,
Security,
Scalabilty,
etc.
System
deployed
17
Testausohjattu ohjelmistokehitys (Test-driven
development, TDD)
• Ohjelmoija kirjoittaa testimäärittelyt ja testikoodin
• Testit laaditaan ennen koodattavan moduulin,
luokan, tms. toteutusta (usein jo ennen lopullista
suunnittelua)
• Sovelluskoodi kirjoitetaan täyttämään testien
sisältämät vaatimukset (testit ovat moduulin
spesifikaatio)
• Testaus ohjaa kehitystyötä (ei ole erillinen
laadunvarmistusvaihe toteutuksen jälkeen)
– testien on aluksi (ennen toteutuksen valmistumista)
epäonnistuttava (pyritään varmistamaan, että testit todella
testaavat haluttua asiaa)
– toiminnallisuus katsotaan toteutetuksi, kun testit menevät
18
läpi
Yksikkötestaus (unit testing)
• Testausohjattu kehitys alkaa yksikkötestauksella
• Yksikkötestin yksikkö on yleensä luokka
– testattava luokka eli testin kohde (voi olla myös luokan osa
tai muutaman toisiinsa kiinteästi liittyvän luokan joukko)
– testiluokka eli testin suorituksen ja resurssit määrittelevä
luokka (tai luokkajoukko)
• Pienin itsenäisesti suoritettava testin osa (yleensä
testiluokan metodi) on testitapaus (test case)
• Testitapauksia kootaan tyypillisesti suuremmiksi
kerralla suoritettaviksi testikokoelmiksi (test suite)
19
Mihin testikoodi sijoitetaan?
• Jokaisen testattavan yksikön (luokan) sisään
– esim. Javassa main-metodiin tai
– staattiseen sisäiseen luokkaan
• Erillisiin testiluokkiin
– yleensä käytetään geneeristä testauskehystä
– JUnit on (erityisesti XP:n muiden ketterien
ohjelmisto-prosessien yhteydessä) suosittu
testauskehys
20
JUnit
*
Test
run(TestResult)
Account
deposit(double)
…
TestCase
TestSuite
run(TestResult)
runTest()
setUp()
tearDown()
run(TestResult)
addTest(Test)
AccountTest
setUp()
testDeposit()
…
21
Yksikkötestausesimerkki (black-box)
Method testLogin() in CActionerTest
void testLogin(){
CActioner actioner = new CActioner();
try{
IAEmployee emp = actioner.login(“user”,”passwd”);
assertEquals(emp.getLoginName(), “user”);
}catch(Exception exc){
fail(“Exception occurs during login”);
}
}
Method login() in CActioner
private IAEmployee emp;
...
public Object login( String username, String passwd ) {
emp = broker.login( username, passwd );
}
22
Yksikkötestaus oliojärjestelmässä
• Oliojärjestelmässä toiminnallisuus tyypillisesti
toteutetaan olioverkon yhteistyönä
• Edellisen kalvon yksikkötestausesimerkki testaa
olioverkkoa mustana laatikkona, joka joko toimii tai
ei toimi
• Sana yksikkötestaus kuitenkin viittaa ajatukseen,
jonka mukaan jokainen testattava yksikkö olisi
itsenäisesti testattavissa
• Eräs ratkaisu on kehittää kullekin luokalle
testausluokkien ympäristö (mock objects), jossa
testattavat oliot voivat toimia yhteistyössä
23
MockFrequency
• Radioesimerkissä vaihdettiin radio
kommunikoimaan radiotaajuutta simuloivan
Frequency-luokan olioiden kanssa
• Radiotaajuus-olion tehtävänä saattaisi olla välittää
oliolle lähetetyt viestit kaikille järjestelmän radioille,
jotka ovat virittäytyneet kuuntelemaan ko. taajuutta
• Vrt. Observer-pattern
• Radiotaajuus-oliota testattaessa testataan siis
viestinvälityksen toimivuutta;
• Radion check-metodia testattaessa tarkistaan, että
radio testissään todellakin käy kaikilla kanavilla
24
MockFrequency
• Radion metodin check() yksikkötestiä varten
tehdään uusi luokka, MockFrequency, jota
käytetään yhdessä yksikkötestaavan luokan kanssa
• Radion metodin check() yksikkötesti onnistuu,
mikäli radio metodissaan läpikäy jokaisen kanavan
• MockFrequency-luokkaan kirjoitetaan
yksikkötestitapauksen kannalta olennainen
toiminnallisuus
• Kaikkia Frequency-luokan toiminnallisuuksia /
vastuita ei tarvitse (eikä edes pidä!) toteuttaa
25
MockFrequency.java
public class MockFrequency implements Frequency {
private boolean checked = false;
public MockFrequency(double d) { }
public boolean transmissionTest() {
return checked = true;
}
public boolean isChecked() {
return checked;
}
public void transmit(String str) { /* NOOP */ }
}
26
Hyväksymistestaus (acceptance testing)
• Testataan toteutettu koodi erikseen toteutuksen
jälkeen
• Kattaa usein laajempia toiminnallisuuskokonaisuuksia kuin yhden luokan (jopa koko
järjestelmän)
• Tarkistetaan verifiointipisteissä (verification point),
että käyttötapauksissa kuvatut vaatimukset
toteutuvat
• Yleensä mustalaatikkotestausta (black-box testing)
– ei huomioida järjestelmän sisäistä toteutusta tai toimintaa,
vaan verrataan ainoastaan syötteitä saatuihin tulosteisiin
– annetaan usein automaattisesti tuotettuina testiskripteinä
– testaaja suorittaa manuaalisesti käyttöliittymän kautta ne
testit, joita ei voida automatisoida
27
Regressiotestaus
• Järjestelmän muutoksen jälkeen uudelleensuoritettavat relevantit hyväksymistestit
– koskevat muuttuneita osia ja niistä riippuvia osia
• Tarkoituksena varmistaa, että
– muutokset ja korjaukset on toteutettu oikein
– muutokset eivät ole aiheuttaneet ei-toivottuja
sivuvaikutuksia
• Olennaista
– testien automatisointi mahdollisimman pitkälle
– turhan testauksen välttäminen, jos mahdollista
• Regressiotestiin (kuten hyväksymistestiinkin) liittyy
– testiskripti ja sen toteutus (tai testin suoritusjärjestelmä)
– syötteiden ja odotettujen tulosten spesifikaatiot
– testidokumentti, jossa raportoidaan testin tulokset
28