Factory Girl 201

Hva du skal skape

Min andre artikkel om denne populære og nyttige Ruby-perlen omhandler et par mer nyanserte emner som nybegynnere ikke nødvendigvis trenger å bekymre seg med med en gang når de kommer i gang. Igjen gjorde jeg mitt beste for å holde det nybegynner-tilgjengelig og forklare hver eneste bit av folk som er nye til Test-Driven Development (TDD), kan snuble over.

emner

  • Avhengige attributter
  • Transient attributter
  • Lazy attributter
  • Endre fabrikker
  • callbacks
  • foreninger
  • aliaser
  • trekk

Avhengige egenskaper

Hvis du trenger å bruke attributtverdier for å komponere andre fabrikkattributter på fly, har Factory Girl dekket deg. Du trenger bare å pakke attributtverdien i en blokk og interpolere attributene du trenger. Disse blokkene har tilgang til en evaluator-som er gitt til dem - og som igjen har tilgang til andre attributter, selv forbigående.

FactoryGirl.define gjør fabrikken: supervillain gjør navnet 'Karl Stromberg' lidenskap 'marine biologi' ambisjon 'menneskelig utryddelse' motivasjon 'redde havets profil "# name har en lidenskap for # lidenskap og har som mål å # motivasjon  gjennom # ambisjon. " ende ende skurk = opprett (: supervillain) villain.profile # =>" Karl Stromberg har en lidenskap for marine biologi og har som mål å redde havene gjennom menneskelig utryddelse. " 

Transient Attributter

Jeg synes det er rimelig å kalle dem falske attributter. Disse virtuelle attributter tillater deg også å sende flere alternativer når du konstruerer fabrikkinstansene dine - via en hash selvfølgelig. Eksemplet i seg selv vil ikke bli påvirket av dem, siden disse attributter ikke vil bli angitt på fabrikkobjektet. På den annen side behandler Factory Girl transient attributter akkurat som ekte.

Hvis du bruker attributes_for, de vil ikke dukke opp skjønt. Avhengige attributter og tilbakeringinger kan få tilgang til disse falske attributter i fabrikken. Samlet sett er de en annen strategi for å holde fabrikkene tørre.

FactoryGirl.define gjør fabrikken: supervillain gjør forbigående gjør megalomaniac falsk cat_owner falsk sluttnavn 'Karl Stromberg' lidenskap 'marine biologi' ambisjon 'menneskelig utryddelse' motivasjon "Bygge en undervanns sivilisasjon # " og redde verden "hvis megalomaniac" profil "Insane business tycoon # " - venner med Blofeld "hvis cat_owner" endend skurk = opprett (: supervillain) villain.profile # => "Sinnsyk forretningsmagasin" villain.motivation # => "Bygg en undervanns sivilisasjon "cat_friendly_villain = create (: supervillain, cat_owner: true) cat_friendly_villain.profile # =>" Insane business tycoon - venner med Blofeld "narcissistic_villain = create (: supervillain, megalomaniac: true) narcissistic_villain.motivation # =>" Bygg en undervanns sivilisasjon og redder verden " 

Eksemplet ovenfor viser seg å være litt mer tørt siden det ikke var nødvendig å opprette separate fabrikker for overvåkere som ønsker å redde verden eller er venner med Blofeld henholdsvis. Transient attributter gir deg fleksibiliteten til å gjøre alle typer tilpasninger og unngå å skape en rekke noensinne så liknende fabrikker.

Lazy Attributes

"Normal" attributter i Factory Girl blir evaluert når fabrikken er definert. Du gir vanligvis statiske verdier som parametere til metoder med samme navn som dine attributter. Hvis du vil forsinke evalueringen til det siste mulige øyeblikk - når forekomsten blir instantiated-må du matche attributter deres verdier via en kodeblokk. Foreninger og dynamisk opprettede verdier fra objekter som Dato tid Objekter vil være dine hyppigste kunder for den dovne behandlingen.

FactoryGirl.define gjør fabrikken: exploding_device gjør transient gjøre countdown_seconds 10 * 60 time_of_explosion Time.now + countdown_seconds sluttid_of_explosion "Eksploderer i # countdown_seconds sekunder # time_of_explosion.strftime (" ved% I:% M% p ")  " slutten ticking_device = create (: exploding_device) ticking_device.time_of_explosion # =>" Eksploderer i 600 sekunder klokka 11:53 " 

Endre fabrikker

Dette er sannsynligvis ikke et brukssak du vil komme inn i hver dag, men noen ganger arver du fabrikker fra andre utviklere, og du vil endre dem - i tilfelle du bruker en TDD'd perle for eksempel. Hvis du føler at du må tilpasse disse eldre fabrikkene for å bedre passe dine spesifikke testscenarier, kan du endre dem uten å skape nye eller bruke arv.

Du gjør dette via FactoryGirl.modify, og det må være utenfor det bestemte FactoryGirl.define blokkere det du vil endre. Det du ikke kan gjøre er å endre sekvens eller trekk-Du kan overstyre attributter definert via trekk selv om. Tilbakeringinger på "original" fabrikken vil heller ikke bli tilsidesatt. Tilbakekallingen i din Factory.modify blokk vil bare bli kjørt som neste i kø.

FactoryGirl.define gjør fabrikken: spion navnet 'Marty McSpy' ferdigheter 'Spionasje og infiltrering' deployment_status 'Forberedelse av oppdrag' endeend FactoryGirl.modify gjøre rekkefølge: mission_deployment do | number | "Mission # number på # DateTime.now.to_formatted_s (: short)" sluttfabrik: spion navn James Bond 'ferdigheter' CQC og poker 'favoritt_weapon' Walther PPK 'body_count' Classified 'favorite_car' Aston Martin DB9 'distribusjon generere (: mission_deployment) slutten 

I eksemplet ovenfor trengte vi at våre spioner skulle være litt mer "sofistikerte" og bruke en bedre mekanisme for å håndtere distribusjon. Jeg har sett eksempler hvor perleforfattere måtte forholde seg til tiden annerledes, og hvor det var praktisk å endre fabrikkobjekter ved å bare tvinge ting du må tweak.

callbacks

Tilbakeringinger tillater deg å injisere en kode på ulike øyeblikk i en gjenstands livscykel lagre, after_save, before_validation og så videre. Rails, for eksempel, tilbyr en hel haug med dem og gjør det ganske enkelt for nybegynnere å misbruke denne kraften.

Husk at tilbakekallinger som ikke er knyttet til bestandighetens gjenstander, er et kjent antimønster, og det er godt å ikke krysse den linjen. For eksempel kan det virke som om det er praktisk å bruke tilbakering etter å ha gitt noe som brukeren å sende e-post eller behandle noen ordre, men slike ting inviterer bugs og skaper bånd som er unødvendig vanskelig å refactor. Kanskje det var en av grunnene til at Factory Girl "only" gir deg fem tilbakeringingsalternativer for å leke med:

  • før (: skape) kjører en kodeblokk før fabrikkinstansen din er lagret. Aktiveres når du bruker skaper (: some_object).
  • etter (: skape) kjører en kodeblokk etter at fabrikkinstansen din er lagret. Aktiveres når du bruker skaper (: some_object).
  • etter (: build) kjører en kodeblokk etter at fabrikkobjektet er innebygd i minnet. Aktiveres når du bruker begge bygge (: some_object) og skaper (: some_object).
  • etter (: stub) kjører en kodeblokk etter at fabrikken har opprettet et stubbet objekt. Aktiveres når du bruker build_stubbed (: some_object).
  • definert (: your_custom_callback) utfører en tilpasset tilbakeringing uten å måtte prepend før eller etter.
FactoryGirl.define gjør fabrikken: oppgave gjør objektiv 'Stoppe den dårlige fyren' provided_gadgets 'Mini ubåt og hajpistol' etter (: bygge) assign_support_analyst slutten 

Oppmerksomhet!

Merk at for alle tilbakeringingsalternativer, inne i tilbakekallingsblokkene, får du tilgang til en instans av fabrikken via en blokkparameter. Dette vil komme til nytte hver eneste gang, spesielt med foreninger.

FactoryGirl.define gjør fabrikken: double_agent do after (: stub) | double_agent | assign_new_identity (double_agent) slutten 

Nedenfor har en ninja en haug med ekkel kaster stjerner (shuriken) til hans disposisjon. Siden du har en ninja gjenstand i tilbakekallingen, kan du enkelt tildele kastestjernen til å tilhøre Ninja. Ta en titt på delen om foreninger hvis det eksempelet gir deg et par spørsmålstegn.

FactoryGirl.define gjør fabrikken: ninja gjør navnet "Ra's al Ghul" fabrikk: ninja_with_shuriken gjør forbigående gjør number_of_shuriken 10 end etter (: create) do | ninja, evaluator | create_list (: shuriken, evaluator.number_of_shuriken, ninja: ninja) slutten slutten fabrikk: shuriken gjør navnet 'Hira-shuriken' number_of_spikes 'Fire ninja ende ende ninja = create (: ninja) ninja.shurikens.length # => 0 ninja = opprett (: ninja_with_shuriken) ninja.shurikens.length # => 10 ninja = opprett (: ninja_with_shuriken, number_of_shuriken: 20) ninja.shurikens.length # => 20 

Også gjennom evaluatorobjektet har du tilgang til forbigående attributter også. Det gir deg muligheten til å passere i tilleggsinformasjon når du "lager" fabrikkobjekter og må tilpasse dem på farten. Det gir deg all den fleksibiliteten som trengs for å spille med foreninger og skrive ekspressive testdata.

Hvis du finner behov for å få flere tilbakeringinger på fabrikken, står Factory Girl ikke i veien, til og med flere typer. Naturligvis er rekkefølge for utførelse topp til bunn.

FactoryGirl.define gjør fabrikken: henchman gjør navn 'Mr. Hinx 'after (: create) | henchman | henchman.send_on_kill_mission etter (: opprett) send_cleaner slutten 
FactoryGirl.define gjør fabrikken: bond_girl gjør navnet 'Lucia Sciarra' etter (: build) | bond_girl | bond_girl.hide_secret_documents etter (: opprett) close_hidden_safe_compartment slutten 

Djevelen er i detaljene selvfølgelig. Hvis du bruker skaper (: some_object), både etter (: build) og etter (: skape) tilbakeringinger vil bli utført.

Flere byggestrategier kan kombineres for å utføre samme tilbakeringing også.

FactoryGirl.define gjør fabrikken: spion gjør navnet 'Marty McFly' etter (: stub,: build) | spion | spy.assign_new_mission slutten 

Sist men ikke minst, kan du til og med sette opp noe som "global" tilbakeringinger som overstyrer tilbakeringinger for alle fabrikker - i hvert fall i den aktuelle filen hvis du har separert dem i flere fabrikkfiler.

fabrikker / gun.rb

FactoryGirl.define gjør før (: stub,: build,: create) | object | object.assign_serial_number fabrikk: spy_gun gjøre navn 'Walther PPK' ammunisjon '7.65mm Browning' forening: eierfabrik: golden_gun gjør navnet 'Custom Lazar' ammunisjon '24-karat gullkule 'etter (: create) | golden_gun | golden_gun.erase_serial_number slutten slutten 

Oppmerksomhet!

Hvis du bruker arv til å komponere barnfabrikker, vil tilbakekallingen på foreldrene også bli arvet.

The Last Mile

La oss ta med alt sammen i følgende avsnitt om foreninger og trekk-ja, jeg snublet også inn alias fordi det var det beste stedet uten å hoppe over alt. Hvis du har betalt oppmerksomhet og husk ting fra den første artikkelen, bør alt falle ganske pent på plass nå.

foreninger

Foreninger er avgjørende for alle selvrespektive nettapplikasjoner som har litt kompleksitet. Et innlegg som tilhører en bruker, en liste som har mange rangeringer og så videre, er brød- og smørutviklerne til frokost hver dag i uken. Sett fra det perspektivet blir det åpenbart at fabrikkene for mer komplekse scenarier må være kollisikre og lette å håndtere, i hvert fall for ikke å rote med TDD mojo.

Emulerende modellforeninger via Factory Girl er relativt grei, vil jeg si. Det som i seg selv er ganske utrolig i mitt sinn. Å oppnå et høyt nivå av enkelhet og bekvemmelighet for å bygge komplekse datasett gjør at TDDs praksis er en no-brainer og så mye mer effektiv.

Den nye Q har hacker ferdigheter og trenger å eie en anstendig datamaskin, ikke sant? I dette tilfellet har du en Datamaskin klassen og dens forekomster tilhører forekomster av Quarter klasse. Lett, rett?

FactoryGirl.define gjør fabrikken: quartermaster gjør navn 'Q' ferdigheter 'Oppfinner ting' sluttfabrikk: datamaskinmodell 'Custom Lenovo ThinkPad W-serie' quartermaster end-ende 

Hva med noe litt mer involvert? La oss si at våre spioner bruker a våpen det har mange patroner (kuler).

klassekassett < ActiveRecord::Base belongs_to :gun end class Gun < ActiveRecord::Base has_many :cartridges end 
FactoryGirl.define gjør fabrikken: patron gjør kaliber '7.65' pistol ende fabrikk: pistol gjør navn 'Walther PPK' ammunisjon '7.65mm Browning' kaliber '7.65' fabrikk: gun_with_ammo gjør forbigående do magazine_size 10 ende etter (: create) do | gun , evaluator | create_list (: patron, evaluator.magazine_size, pistol: gun) slutten slutten slutten 

Tilbakeringinger kommer ganske bra med foreninger, va? Nå kan du bygge en pistol med eller uten ammunisjon. Via hash pistol: pistol du ga patron fabrikk med nødvendig informasjon for å opprette foreningen via fremmed.

spy_gun = create (: gun) spy_gun.cartridges.length # => 0 spy_gun_with_ammo = opprett (: gun_with_ammo) spy_gun_with_ammo.cartridges.length # => 10 

Hvis du trenger en annen magasinstørrelse, kan du sende den inn via din forbigående attributt.

big_magazine_gun = create (: gun_with_ammo, magazine_size: 20) big_magazine_gun.cartridges.length # => 20 

Så hva med de ulike byggestrategiene? Var det ikke noe fisket der? Vel, her er hva du trenger å huske: Hvis du bruker skape for tilknyttede objekter, vil begge bli lagret. Så skaper (: Quartermaster) vil bygge og lagre både Q og hans ThinkPad.

Jeg vil bedre bruke bygge, da, hvis jeg vil unngå å treffe databasen, ikke sant? God ide, men bygge ville bare gjelde for kvartermester i vårt eksempel - den tilknyttede datamaskin vil fortsatt bli reddet. Litt vanskelig, vet jeg. Her er hva du kan gjøre hvis du trenger å unngå å lagre det tilknyttede objektet - du angir byggestrategien du trenger for din tilknytning.

FactoryGirl.define gjør fabrikken: quartermaster gjøre navn 'Q' ferdigheter 'Oppfinner ting' sluttfabrikk: datamaskinmodell 'Custom Lenovo ThinkPad W Series' forening: quartermaster, strategi:: bygge endeend 

Du navngir det tilknyttede fabrikkobjektet og passerer i en hash med din byggestrategi. Du må bruke det eksplisitte assosiasjon ring for dette til å fungere. Eksempelet nedenfor virker ikke.

Fabrikk: Datamodell 'Custom Lenovo ThinkPad W Series' quartermaster, strategi:: build end 

Nå bruker begge objektene bygge og ingenting blir lagret i databasen. Vi kan sjekke antakelsen ved å bruke ny rekord?, som returnerer ekte hvis forekomsten ikke har vært vedvarende.

thinkpad = build (: computer) thinkpad.new_record? # => sant thinkpad.quartermaster.new_record? # => sant 

Mens vi er på det, via det eksplisitte assosiasjon ring deg kan også referere til forskjellige fabrikk navn og endre attributter i fly.

FactoryGirl.define gjør fabrikken: quartermaster gjør navn 'Q' end fabrikk: datamaskinmodell 'Custom Lenovo ThinkPad W Series' forening: hacker, fabrikk :: quartermaster, ferdigheter: 'Hacking' end-end 

La oss lukke dette kapitlet med et eksempel som er polymorfe.

klassespion < ActiveRecord::Base belongs_to :spyable, polymorpic: true end class MIFive < ActiveRecord::Base has_many :spies, as: :spyable end class MISix < ActiveRecord::Base has_many :spies, as: :spyable end 
FactoryGirl.define gjør fabrikken: Mifive gjør navnet 'Military Intelligence, Seksjon 5' principal_activity 'Endelig fabrikk: Misix do name' Militær intelligens, seksjon 6 'principal_activity' Utenlandsk motintelligens 'endefabrikk: mifive_spy, klasse: Spy gjør navn 005 'forening: spyable, fabrikk :: mifive ende fabrikk: misix_spy, klasse: Spy navn 006' forening: spyable, fabrikk :: misix ende ende # MI5 agenter mifive = create (: mifive) mifive_spy = opprette (: mifive_spy) mifive.spies << mifive_spy mifive.name # => "Military Intelligence, Section 5" mifive_spy.name # => '005' mifive.spies.length # => 1 mifive.spies.first.name # => '005' # MI6-agenter misix = opprett (: misix) misix_spy_01 = opprett (: misix_spy, navn: '007') misix_spy_02 = opprett (: misix_spy) misix.spies << misix_spy_01 misix.spies << misix_spy_02 misix.name # => "Military Intelligence, Section 6" misix.spies.length # => 2 misix_spy_01.name # => '007' misix_spy_02.name # => '006' misix.spies.first.name # => '007' 

Ikke føl deg dårlig hvis denne trenger litt mer tid til å synke inn. Jeg anbefaler å ta opp på polymorfe foreninger hvis du er usikker på hva som skjer her.

aliaser

Aliaser for fabrikkene gir deg mulighet til å være mer uttrykksfulle for konteksten du bruker dine fabrikkobjekter i. Du trenger bare å gi en hash av alternative navn som bedre beskriver forholdet mellom tilknyttede objekter.

La oss si at du har en :middel fabrikk og a : law_enforcement_vehicle fabrikk. Ville det ikke vært fint å referere til agenten som :Eieren i sammenheng med disse bilene? I eksemplet nedenfor kontraste jeg det med et eksempel uten et alias.

FactoryGirl.define gjør fabrikken: agent, aliaser: [: eier] navnet Fox Foxes jobb 'Chasing bad dudes' special_skills 'Investigation and intelligence' fabrikk: double_O_seven navnet James Bond 'end-end fabrikk: law_enforcement_vehicle gjør navnet' Oldsmobile Achieva 'snille' kompaktbil ': eierens endefabrik: spy_car gjøre navn' Aston Martin DB9 'snill' Sportsbil 'double_O_seven ende ende 

Oppmerksomhet!

Ikke glem å legge til et kolon foran den aliased fabrikken (:Eieren) når du bruker dem til foreninger i fabrikkene dine. Dokumentasjonen og mange blogginnlegg bruker dem uten kolon i disse tilfellene. Alt du får er sannsynligvis a NoMethodError fordi du mangler en setter-metode for det aliaset nå. (Jeg vil bedre åpne en trekkforespørsel.) Første gang jeg løp inn i dette, forvirret det meg og tok meg litt for å komme forbi det. Husk å noen ganger selektivt mistillidsdokumentasjon og blogginnlegg. Selvfølgelig også, selvsagt.

Jeg tror du er enig i at bruk av aliaser ikke bare leser bedre, men gir deg også, eller personen som kommer etter deg litt mer sammenheng med de aktuelle objektene. Ja, du må bruke flertall : aliaser også hvis du bare har et enkelt alias.

Du kan også skrive dette litt annerledes - mye mer verbosely.

fabrikk: agent, aliaser: [: mulder] heter navnet "Fox Mulder" jobben "Chasing bad dudes 'special_skills' Undersøkelse og etterretnings endefabrik: Law_enforcement_vehicle gjør navn 'Oldsmobile Achieva' type 'Kompakt bil' forening: eier, fabrikk ::: agent ende 

Vel, ikke så pent, er det?

Selvfølgelig kan du også bruke disse aliasene til å "bygge" fabrikkobjekter med en gang.

fbi_agent = create (: mulder) fbi_agent.name # => 'Fox Mulder' 

I sammenheng med kommentarer, a :bruker kan bli referert til som : commenter, i tilfelle av a :forbrytelse en :bruker kan bli alias som en :mistenkt, og så videre. Det er ikke rakettvitenskap virkelig-mer som praktisk syntaktisk sukker som reduserer fristelsen for duplisering.

trekk

Dette er en av mine favoritt ting om Factory Girl. I et nøtteskall er egenskaper lego-lignende blokker for å bygge fabrikkene dine og blande seg i atferd. De er kommaseparerte lister over symboltrekk / attributter som du vil legge til på en bestemt fabrikk, og de er også definert i fabrikkens fil (er).

I tankene mine, trekk er den mest kraftige og praktiske funksjonen for å holde fabrikkdataene dine tørre samtidig som de er uttrykksfulle. Det lar deg kombinere grupper av attributter sammen, gi dem separate navn, og gjenbruk dem hvor du vil. Husk da jeg oppfordret deg til å definere barebenet fabrikkobjekter? Egenskaper vil hjelpe deg å oppnå akkurat det uten å ofre noe.

FactoryGirl.define gjør fabrikken: spy_car modell 'Aston Martin DB9' top_speed '295 km / h' build_date '2015' ejection_seat sant trekk: ubåt utstøting sjølv falskt vannresistent '100 m' submarine_capabilities true air_independent_propulsion sant endeegenskap: weaponized do raketter sant number_of_rockets '12' machine_gun true rate_of_fire '1500 RPM' tank_armour true ende-egenskap: cloaked gjør active_camouflage true radar_signature 'reduced' engine 'silenced' ende egenskap: night_vision gjør infrared_sensors true heads_up_display true end end end 

Som du kan se, hvis du vil endre noen attributter som er spredt over flere objekter, kan du gjøre det nå på ett sentralt sted. Ingen haglgevær kirurgi nødvendig. Managing state via egenskaper kunne ikke være mer praktisk.

Med det oppsettet kan du bygge ganske forseggjorte spionbiler ved å blande de forskjellige attributtbuntene, men du vil-uten å duplisere noe via å lage alle slags nye fabrikker som står for alle de forskjellige alternativene du trenger.

invisible_spy_car = create (: spy_car,: cloaked,: night_vision) diving_spy_car = opprett (: spy_car,: ubåt,: cloaked) tank_spy_car = create (: spy_car,: weaponized,: night_vision) 

Du kan bruke trekk med skape, bygge, build_stubbed og attributes_for. Hvis Q blir smart, kan du også overstyre individuelle attributter samtidig ved å passere i en hash.

bygge (: spy_car,: ubåt, ejection_seat: true) 

For egenskapskombinasjoner som forekommer svært ofte på en bestemt fabrikk, kan du også opprette barnfabrikker med navn som best representerer de forskjellige datasettkombinasjonene. På den måten kombinerer du bare trekk i forhold til hele tiden når du lager testdata.

FactoryGir.define gjør fabrikken: Spy_car modell "Aston Martin DB9 'top_speed' 295 km / h 'build_date' 2015 'ejection_seat sant trekk: ubåten gjør ... endeegenskap: weaponized do ... endeegenskap: cloaked do ... endefigur: night_vision do ... Endelig fabrikk: invisible_spy_car, trekk: [: cloaked, night_vision] fabrikk: diving_spy_car, trekk: [: submarine,: cloaked] fabrikk: tank_spy_car, trekk: [: weaponized,: night_vision] fabrikk: ultimate_spy_car, trekk: [: cloaked ,: night_vision,: ubåt,: weaponized] ende 

Dette lar deg lage disse objektene mer konsistent, og det er mer lesbart også.

build_stubbed (: invisible_spy_car) opprette (: ultimate_spy_car) 

I stedet for:

build_stubbed (: spy_car,: cloaked,: night_vision) create (: spy_car,: cloaked,: night_vision,: ubåten,: weaponized) 

Leser mye bedre, nei? Spesielt når ingen variable navn er involvert.

Du kan til og med gjenbruke egenskaper som egenskaper på andre egenskaper og fabrikker. Hvis du definerer de samme attributter for flere egenskaper, blir den sist definerte forrang, selvfølgelig.

FactoryGirl.define gjør fabrikken: spy_car modell 'Aston Martin DB9' top_speed '295 km / h' build_date '2015' ejection_seat sant trekk: ubåten gjør ... endeegenskap: weaponized do ... endeegenskap: cloaked do ... endefigur: night_vision do ... Endelig trekk: mobile_surveillance gjør cloaked natt_vision signal_detektor sant signal_analyzer sant wifi_war_driver sant license_plate_reader sann mini_drone sann sluttfabrik: ultimate_spy_car, foreldre:: spy_car do car_plane true ubåten weaponized mobile_surveillance ende ende 

Vær oppmerksom på mobile_surveillance egenskap som gjenbruker maskert og nattsyn egenskaper - i utgangspunktet som et attributt. Også ultimate_spy_car fabrikk, som jeg skilt ut av spy_car Fabriksdefinisjonen for moro denne gangen, gjenbruk alle trekk pluss en ekstra attributt som gjør det også flyr. Ren film magi - eller kanskje jeg burde si Factory Girl magic.

create_list og build_list kan også gjøre bruk av trekk. Den andre parameteren må være antall fabrikkinstanser du vil ha.

create_list (: spy_car, 3,: night_vision) build_list (: spy_car, 4,: ubåt,: cloaked) 

Ville det ikke vært kult å bruke foreninger med egenskaper? Selvfølgelig kan du pakke tilbakekallinger og foreninger pent inn i trekk. duh!

FactoryGirl.define gjør fabrikken: patronen er snill 'Liten calliber pistol ammunisjon' kaliber '7.65' prosjektil 'Lead' gun fabrikk: golden_cartridge do projectile 'Gold' forening: pistol,: Golden End End Factory: Gun Name "Walther PPK 'ammunisjon '7.65mm Browning' kaliber '7.65' forbigående do magazine_size 10 endeegenskaper: golden name 'Custom Lazar' ammunisjon '23-karat gullkule 'endeegenskaper: with_ammo do after (: create) do | gun, evaluator | create_list (: patron, evaluator.magazine_size, pistol: gun) slutten trekk: with_golden_ammo gjøre etter (: create) do | golden_gun, evaluator | create_list (: golden_cartridge, evaluator.magazine_size, pistol: golden_gun) endeendens ende ende 

Hvordan bruke dem skal være kjedelig nå.

 patron = opprette (: patron) patron.projektil # => 'Lead' patron.gun.name # => 'Walther PPK' patron.gun.ammunition # => '7.65mm Browning' patron.gun.caliber # => ' 7.65 'golden_cartridge = create (: golden_cartridge) golden_cartridge.projectile # =>' Gold 'golden_cartridge.gun.name # =>' Custom Lazar 'golden_cartridge.gun.ammunition # => '23-karat gullkule' golden_cartridge.gun.caliber # => '7.65' gun_with_ammo = opprett (: pistol,: med_ammo) gun_with_ammo.name # => 'Walther PPK' gun_with_ammo.ammunition # => '7.65mm Browning' gun_with_ammo.cartridges.length # => 10 gun_with_ammo.cartridges. first.projectile # => 'Lead' gun_with_ammo.cartridges.first.caliber # => '7.65' golden_gun_with_golden_ammo = opprett (: gun,: golden,: with_golden_ammo) golden_gun_with_golden_ammo.name # => 'Custom Lazar' golden_gun_with_golden_ammo.ammunition # = > '24-karat gullkule 'golden_gun_with_golden_ammo.cartridges.length # => 10 golden_gun_with_golden_ammo.cartridges.first.projectile # =>' Gull ' golden_gun_with_golden_ammo.cartridges.first.caliber # => '7.65' 

Siste tanker

Siste visdomsord: Endring er din faste følgesvenn - trenger å endre attributter eller datatyper skjer hele tiden. Designbeslutninger som disse utvikler seg. Egenskaper vil lindre smerten med det og hjelpe deg med å administrere datasettene dine.

Tenk deg om du hadde brukt en alternativ hash for instantiation og det kravet endret seg helt. Hvor mange potensielle steder i testene dine kan bryte og vil nå trenge oppmerksomhet? Rett opp, trekk er et veldig effektivt verktøy for å eliminere duplisering i testpakken. Men med all den bekvemmeligheten, vær ikke lat og glem din enhetstester på kolonnene som er representert av dine egenskaper! På den måten gir du dem like mye omsorg som bare-beinattributtene som trengs for gyldige objekter.

Det er litt mer å oppdage i Factory Girl, og jeg er sikker på at du nå er mer enn godt rustet til å sette sammen stykkene når du trenger dem. Ha det gøy å leke med denne perlen. Jeg håper at dine TDD-vaner vil dra nytte av det.