Innstalasjon og Testing
I denne oppgaven skal du implementere applikasjonen (funtemps
) etter en spesifikasjon.
Det er følgende ting som du må ha på plass (godkjent på seminaret og konfigurert på din datamaskin) før du begynner å implementere applikasjonen:
funtemps
på Github for denne oppgaven (laget repository i Github og valgt README.md og .gitignore for Go).funtemps
(Github kontonavn vil bli publisert i Canvas).go.mod
fil i prosjektets mappe; miljøvariabelen GO111MODULE
skal være "on").fib
fra seminaret).
1 Spesifikasjon funtemps
En av prinsippene bak design av Unix (og Linux) operativsystemet er modularitet. Systemverktøy, for å administrere, monitorere og konfigurere systemet er små programmer (kommandoer eller moduler; OBS! moduler i denne sammenhengen er ikke det samme som Go moduler), som hver gjør en ting veldig bra (er godt testet, blant annet på forskjellig maskinvare). Administrasjon av et datasystem ofte består av gjentagelse av de samme operasjonene (kopiere filer, endre filer, sende/motta filer, observere prosesser, observere maskinvare, kompilere programmer, starte/stoppe prosesser/programmer osv.). Slike gjentagende operasjoner kan da bli implementert som kommandolinjeapplikasjoner. Brukere av operativsystemet bruker slike stabile programmer til å utvikle videre sine egne programmer (systemet er utvidbart/programmerbart). I denne oppgaven skal du planlegge og implementere et program (kommando, fordi at den skal starte fra kommandolinje med inn-data på kommandolinje og skrive ut svar/ut-data til kommandolinje), som regner om fra en temperaturskala til en annen. I tillegg skal ditt program kunne skrive ut noen "fun-facts" om temperaturer på Solen, Månen og Jorden.
De fleste kommandoene i et Unix(darwin)/Linux operativsystem har et navn, argumenter og flagg. Den generelle formen for et kommando, som startes fra kommandolinje er (den kan variere noe fra en distribusjon av operativsystemet til en annen):
KOMMANDO_NAVN [flagg] [argumenter]
- For eksempel, med et kommando
rm -Rf MAPPENAVN
, som er et av systemprogrammene i Linux, kan man slette en mappe med all innhold (alle eventuelle mapper og filer). rm
, som står for remove, har 2 flaggR
(sletter hele hierarkiet av mapper og filer) ogf
(som betyr at det ikke blir spurt om bekreftelse ... skummelt!), og et argumentMAPPENAVN
, som er selvforklarende.
Du skal implementere et kommando funtemps
(som en Go applikasjon), som tar inn data ved hjelp av flagg, og skriver ut svar til stdout
(en av tre standardstrømmene i Linux/Unix).
Kommandoet, når skrevet inn på kommandolinje, skal oppføre seg på følgende måte (OBS! "Output:" skal ikke skrives ut, kun strengen eller strengene etter "Output:"):
funtemps -K 273.15 -out C
- Output: 273.15K er 0°C
funtemps -F 32 -out C
- Output: 32°F er 0°C
funtemps -C -89.4 -out F
- Output: -89.4°C er -128.92°F
funtemps -C -89.4 -out K
- Output: -89.4°C er -183.75K
funtemps -funfacts sun -t C
- Output: (2 linjer)
Temperatur på ytre lag av Solen 5506.85°C.
Temperatur i Solens kjerne er 15 000 000°C.
Vi skal teste disse kommandoene med våre testfunksjoner, så de må være korrekte. Vi skal også teste noen tilfeldige kombinasjoner av input og output, som ikke er spesifisert ovenfor, for eksempel konvertering mellom temperaturskalaene med tilfeldige verdier (ikke de som er oppgitt ovenfor).
Vi vil også teste at dere kan vise "fun facts" for månen (verdien til flagget skal være luna, - funtemps -funfacts luna
) og jorden (verdien til flagget skal være terra, - funtemps -funfacts terra
).
For formater i output er det følgende krav:
- Input skal alltid presenteres slik som input er på kommandolinje, dvs.
45.567
skal også vises i output med 3 desimaler. Alle beregnede verdier skal vises med 2 desimaler (avrundes). Hvis verdiene er flyttall med kun nuller som desimaler, for eksempel,32.0000000
, så skal kun heltallsdelen vises, -32
. Hvis det er store tall som skal vises som, for eksempel,15 millioner
, så skal de ha mellomrom mellom hver tredje siffer (15 000 000
).
Formlene for konvertering mellom temperaturskalaer (Fahrenheit, Celsius og Kelvin):
Celsius = Kelvin - 273.15
Kelvin = Celsius + 273.15
Farhrenheit = Celsius*(9/5) + 32
Celsius = (Farhrenheit - 32)*(5/9)
Farhrenheit = (Kelvin - 273.15)*(9/5) + 32
Kelvin = (Farhenheit - 32) * (5/9) + 273.15
Diverse temperaturer | |||
---|---|---|---|
"fun fact" | °F | °C | K (Kelvin) |
Høyeste temperatur målt på Jordens overflate | 134 | 56.7 | 329.82 |
Laveste temperatur målt på Jordens overflate | -89.4 | ||
Temperatur i Jordens indre kjerne | 9392 | ||
Temperatur i Solens kjerne | 15000000 | ||
Temperatur på ytre lag av Solen | 5778 | ||
Temperatur på Månens overflate om natten | -183 | ||
Temperatur på Månens overflate om dagen | 106 |
2 Mal for oppgaven
Mal for oppgaven kan dere klone fra uia-worker.
Studer nøye alle instruksjonene i malen. Malen inneholder ikke noen konfigurasjon av Go moduler. Malen skal ikke brukes direkte som repository. Du skal kopiere kildekoden over til din repository, før du begynner gjøre endringer. Pass på å ikke kopiere over .git
mappen fra uia-worker sin repository til din repository, da den skal overskrive din git-historikk.
Figur 1. Mappe- og filstruktur i mal-repository.
3 Kort om test-drevet utvikling
Vi vil gå gjennom et eksempel for test-drevet utvikling på seminaret, så her er det kun en kort notat. Du finner malene for testene i pakke-mappene conv
(forkortelse for en. conversion) og funfacts
.
Når du har konfigurert Go modul korrekt, så skal du kunne bruke go test
for å utføre testene i filene, som har filnavn som slutter på _test.go
.
Det er allerede blitt spesifisert funksjonsnavn som skal testes. For eksempel, hvis man skal teste FarhenheitToCelsius(value float64) float64
så kan man bruke denne koden:
func TestFarhenheitToCelsius(t *testing.T) {
type test struct {
input float64
want float64
}
tests := []test{
{input: 134, want: 56.67},
}
for _, tc := range tests {
got := FarhenheitToCelsius(tc.input)
if !reflect.DeepEqual(tc.want, got) {
t.Errorf("expected: %v, got: %v",
tc.want, got)
}
}
}
Kodefragment 1. Funksjon TestFarhenheitToCelsius fra malen.
Kort sagt (vi vil analysere det dypere på seminaret), gjør denne koden følgende:
- definerer en struktur med to datafelt, ett for input og ett for verdien som vi ønsker å teste mot
- så defineres det en slice, som inneholder testdata, dvs. når input er
134
så ønsker vi å ha output56.67
; denne sammenhengen kommer fra formelen spesifisert i dette dokumentet - så utføres testen ved å utføre en såkalt dyp sammenligning, som vil også gi korrekt svar for strukturer og array, og ikke kun for enkelte verdier (funksjonaliteten er implementert i pakken reflect)
go test
vil kompilere koden og returnere et OK-svar, hvis testen passerer, og feilmelding, hvis ikke
Hvis på det tidspunktet når go test
utføres, finnes det en funksjon i conv.go
filen, som heter FarhenheitToCelsius
, så vil testrammeverket utføre denne funksjonen. I malen ser denne funksjonen slik ut:
// Konverterer Farhenheit til Celsius
func FarhenheitToCelsius(value float64) float64 {
// Her skal du implementere funksjonen
// Du skal ikke formattere float64 i denne funksjonen
// Gjør formattering i main.go med fmt.Printf eller
// lignende
return 56.67
}
Kodefragment 2. Funksjon FarhenheitToCelsius fra malen.
Funksjonen i Kodefragmentet 2 vil tilfredsstille testen, fordi at testdata spesifisert i Kodefragment 1 vil matche med verdien som FarhenheitToCelsius
returnerer.
Men vi ønsker ikke oss en hardkodet returverdi, fordi at da vil funksjonen være korrekt kun for en verdi, dvs. for ett testtilfelle. Hvis vi legger til flere testdata {input: 32, want: 0}
, så vil testen selvsagt feile.
Vi må i neste omgang (se Kodefragment 3) prøve å legge inn en beregning, slik at funksjonen kan beregne konverteringen for vilkårlige verdier (vi bør senere også tenke på hvor store eller små verdier vi ønsker å tillate, men det er ikke et krav i denne oppgaven).
// Konverterer Farhenheit til Celsius
func FarhenheitToCelsius(value float64) float64 {
// Legger inn formellen Celsius = (Farhrenheit - 32)*(5/9)
return (value - 32)*(5/9)
}
Kodefragment 3. Funksjon FarhenheitToCelsius andre versjon under testing.
Nå kan vi spesifisere flere testtilfeller og prøve på nytt med go test
. Det er viktig å spesifisere grensetilfeller, for eksempel, hva er den største verdien vår funksjon vil takle? Hvis vi antar at vi ikke kjenner til temperaturer under 0K og over 15 millioner grader Celsius, så kunne vi lagt inn en kontrollsetning i funksjonen vår. Da trenger vi også å returnere en feil, som vi også må teste. Vi har forløpig ikke sett på feilhåndtering i Go, så det legger vi i mente foreløpig.
Da er oppgavenspesifikasjonen slutt. Ta kontakt med lærere, hvis noe er uklart.
Innlevering skal bestå av lenken til den private github-repositorien og en kort oppsummering i Canvas (slik at vi eventuelt kan gi tilbakemelding gjennom SpeedGrader). Evalueringen skal være i forhold til vurderingsveiledning i form av rubrikkene.
4 Referanser
- Beck, K. (2014). Test-driven development by example. Boston Addison-Wesley.
- KentBeck.com. (2018). Kentbeck.com.