IV praktikum: TDD ja refactoring

Uued jarid, mis tuleb ümber nimetada .jar ja lisada classpathi:

Klassis harjutamiseks

  • TDD (Test Driven Development) - enne mingi funktsiooni koodi kirjutamist kirjutatakse soovitud funktsionaalsust testiv test (mis alguses fail'ib).
  • Refactoring – parema struktuuri, loetavuse vms eesmärgil koodi muutmine, mille käigus ei muutu selle käitumine.
  • Ping-Pong Programming – ühendab endas paaris programmeerimist ja TDD-d. Kaks arendajat on ühe arvuti taga, üks kirjutab testi ja teine paneb selle passima ning kirjutab ise uue testi, mille peab esimene passima panema.

Ülesanne

TDD lähenemist kasutades teha lihtne Calculator class, mis suudab esialgsete nõute kohaselt teha tehteid täisarvudega:

  • liita
  • lahutada
  • teha mitu tehet järjest
  • nullida tulemus ja alustada uue arvutusega
  • oskab printida sooritatud tehte koos tulemusega: nt. „1 + 2 + 3 = 6”

Iga sammu järel tagastab kalkulaator hetke tulemuse.

Eesmärk on luua lihtsaim võimalik lahendus ja loomise käigus ei ole veel teada, et klient soovib tulevikus seda tarkvara muuta.

Refactoring

Klient soovib peale programmi kätte saamist ja mõnda aega kasutamist lisada järgneva funktsionaalsuse:

  • jagamine
  • tagasi liikuda eelmise tehte juurde – näiteks tegid 1 + 2 + 3 - 4, aga avastasid, et tahtsid teha 1 + 2 - 4 + 1, siis saad kaks sammu tagasi liikuda ja jätkata sealt.

Teha vajalikud muudatused programmikoodi (tehted peavad tagastama komadega arve, tuleb hoida ajalugu tehetest jne.). Jätkuvalt kirjutame enne testid ja siis muudame, mitte vastupidi!

Refactoringu käigus tuleks silmas pidada seda, et enne uue funktsionaalsuse lisamist tuleks olemasolevat koodi muuta nii, et seda oleks võimalik lisada aga samas ei tohi muutuda olemasoleva koodi käitumine (testide käivitamisel peavad nad jätkuvalt passima). Selle käigus tuleb kohendada ka teste, kuid nad peavad jätkuvalt testima seda, mida enne.

Näiteks kui esimeses iteratsioonis koostatud kood hoidis resulti int tüüpi muutujas, siis peale jagamise nõude tulemist peab seda hakkama hoidma BigDecimal või double tüüpi muutujas.


Mõlemad klassis lahendatavad ülesanded ülesanded lahendatakse Ping-Pong Programmingut praktiseerides. Selleks valib praktikumijuhendaja välja ühe paari, kes istub arvuti taha millega on ühendatud projektor ja lahendavad üks/kaks kirjeldatud punkti funktsionaalsusest.


Kodutöö

Kirjeldus

  • PurchaseInfoTableModel sisaldab List<SoldItem> (päritud klassist SalesSystemTableModel)ja Sale sisaldab Set<SoldItem>. Sellest dubleerimisest peaks lahti saama. Kõige mõistlikum on panna PurchaseInfoTableModel kasutama Sale objekti ridade saamiseks. Selleks eemaldada klassist SalesSystemTableModel väli List<T> rows ning muuta meetod public List<T> getTableRows abstraktseks, mille iga päriv klass ise implementeeriks.
  • Praegu toimub lao- kliendi- ja ajaloopaanide värskendamine andmete muutmise peale. Realiseerida loogika, kus neid andmeid värskendataks andmebaasist iga kord kui vastav paan aktiveeritakse.
  • Hea oleks kui objektmudeli kasutamine oleks uue ostu sooritamise korral umbes selline:
    • Kasutaja valib kliendi ja selle peale luuakse uus ost
      Client client = …
      Sale sale = new Sale(client);
    • Kasutaja valib toote, ja lisab selle ostule:
      StockItem stockItem = …
      // loob vajadusel sisemiselt SoldItem objekti ja lisab selle ostule või kasutab juba olemasolevat ja muudab lihtsalt kogust
      sale.addItem(stockItem);
    • Kasutaja sooritab ostu:
      sale.setSellingTime(new Date());
      Asendada senine meetod submitCurrentPurchase(List<SoldItem> goods, Client currentClient) uue meetodi vastu:
      salesDomainController.registerSale(sale);
      Kindlasti on vaja muuta ka StockItem’i kogust

Soovituslik tööde järjekord

  • Unustada hetkeks kogu (G)UI ja teha korda vastavalt üleval olevale juhendile objektmudel, alustades unit testidega (JUnit), vajadusel kasutada mockimist (easymock). Tõenäolised testi klassid ja meetodid:
    • SaleTest:
      • testCreation()
      • testAddingSingleItem()
      • testAddingManyItems()
      • testAddingExistingItem()
      • ..
    • SalesDomainControllerImplTest
      • testRegisterSaleWithNoItems()
      • testRegisterSale()
      • testRegisterSaleChangesStockQuantity()
      • ..
  • Teha korda GUI. Alustada SaleSystemTableModel’ist, millest kaob väli rows. Seejärel muuta tablemodeleid - PurchaseInfoTableModelist hakkab kasutama Sale objekti, StockTableModel peab oma ridu ise hoidma.
  • Lisada lao, kliendi ja ajaloo paanidele meetod refresh() sisu värskendamiseks. Tabeli read tuleb lugeda domeeni kontrolleriga andmebaasist ning kirjutada modelisse. Refresh meetod tuleb käivitada igal tabi aktiveerimisel.
  • Code cleanup. Tõenäoliselt jäävad kasutamat mitmed meetodid nii SalesDomainControllerImpl klassis kui ka mujal – kaotada need ära

Testide jaoks teeme eraldi folderi “test”, mille määrame eclipses source folderiks. Iga klassi test peab olema samas package-is ja testklassi nimi peab olema TestitavaKlassiNimiTest.

Kaitsmine

Kaitsmisel peab näitama kirjutatud teste. Hinnatakse seda, kui suurt osa muudetud/lisatud koodist testid katavad, testide loetavust ja piirsituatsioonide kaetust.

Süsteem peab endiselt töötama, kasutades lihtsalt paremat objektmudelit. Funktsionaalsus ei muutu.

Viited:

edit