IV praktikum: TDD ja refactoring

Uued jarid, mis tuleb lisada classpathi:

Klassis harjutamiseks

  • TDD (Test Driven Development) - enne reaalse koodi kirjutamist tehakse test, mis failib
  • 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> ja Sale sisaldab Set<SoldItem>. Sellest dubleerimisest peaks lahti saama. Kõige mõistlikum on panna PurchaseInfoTableModel kasutama Sale objekti ridade saamiseks. Lisaks annab see meile võimaluse korrastada veidi objektmudelit.

Hetkel kasutatakse ostu sooritamiseks ostu andmete hoidmiseks StockTableModelit, selle peaks jätma ainult Ladu tabi jaoks. Ostu sooritamise tabi jaoks võiks olla sarnaselt PurchaseInfoTableModeliga Sale põhine TableModel.

Mõlemad, nii PurchaseInfoTableModel kui ka ostu sooritamise TableModeli jaoks võib olla ühine baasklass sarnase funkstionaalsuse jaoks (tulba nimed, tulpade arv, Sale hoidmine jne).

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());
//submitCurrentPurchase(List goods, Client currentClient) vastu välja vahetada, vaja on kindlasti muuta ka StockItem’i kogust
salesDomainController.registerSale(sale);

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: testCreattion(), testAddingSingleItem(), testAddingManyItems(), testAddingExistingItem(), …
    • SalesDomainControllerImplTest: testRegisterSaleWithNoItems(), testRegisterSale(), testRegisterSaleChangesStockQuantity()
  • Teha korda GUI. Alustada PurchaseInfoTableModel’ist, mis hakkab kasutama Sale objekti, ei või enam extendida SaleSystemTableModel’it vaid AbstractTableModel’it või loodud baasklassi, mis extendib AbstractTableModel’it.
  • 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 classi test peab olema samas packages 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