Mijn tweede artikel over deze populaire en nuttige Ruby-edelsteen gaat in op een paar meer genuanceerde onderwerpen die beginners niet meteen hoeven te maken als ze aan de slag gaan. Nogmaals, ik heb mijn best gedaan om het nieuwbie-toegankelijk te houden en uit te leggen dat elk beetje van de lingo-mensen die nieuw zijn in Test-Driven Development (TDD) over zou kunnen struikelen.
Als u attribuutwaarden moet gebruiken voor het direct samenstellen van andere fabrieksattributen, heeft Factory Girl u gedekt. U hoeft alleen de kenmerkwaarde in een blok in te pakken en de kenmerken die u nodig hebt te interpoleren. Deze blokken hebben toegang tot een evaluator-wat voor hen is toegegeven - en die op zijn beurt toegang heeft tot andere attributen, zelfs voorbijgaande.
FactoryGirl.define doen fabriek: superschurk do naam 'Karl Stromberg' passie 'mariene biologie' ambitie 'human extinction' motivatie 'red de oceanen' profiel "# name heeft een passie voor # passion en streeft naar # motivatie tot # ambition. " end-end schurk = create (: superschurk) villain.profile # =>" Karl Stromberg heeft een passie voor mariene biologie en heeft als doel de oceanen te redden door menselijke uitroeiing. "
Ik denk dat het eerlijk is om ze valse attributen te noemen. Met deze virtuele kenmerken kunt u extra opties doorgeven wanneer u uw fabrieksinstanties bouwt, uiteraard via een hash. De instantie zelf wordt hierdoor niet beïnvloed, omdat deze kenmerken niet worden ingesteld op uw fabrieksobject. Aan de andere kant behandelt Factory Girl voorbijgaande kenmerken, net als echte.
Als je gebruikt attributes_for
, ze zullen echter niet verschijnen. Afhankelijke attributen en callbacks hebben toegang tot deze nepattributen in uw fabriek. Over het algemeen zijn ze een andere strategie om uw fabrieken droog te houden.
FactoryGirl.define do factory: supervillain do transient do megalomaniac false cat_owner valse naam 'Karl Stromberg' passion 'marine biology' ambition 'human extinction' motivation "Een onderwaterwereld beschaving bouwen # " en de wereld redden "als megalomaan" profile "Insane business tycoon # " - vrienden met Blofeld "if cat_owner" end-end villain = create (: superschurk) villain.profile # => "Insane business tycoon" villain.motivation # => "Een onderwatercivilisatie opbouwen "cat_friendly_villain = create (: supervillain, cat_owner: true) cat_friendly_villain.profile # =>" Insane business tycoon - friends with Blofeld "narcissistic_villain = create (: supervillain, megalomaniac: true) narcissistic_villain.motivation # =>" Het bouwen van een onderwaterbeschaving en de wereld redden"
Het bovenstaande voorbeeld blijkt een beetje DROOG te zijn, omdat het niet nodig was om afzonderlijke fabrieken te creëren voor supervillains die de wereld willen redden of vrienden zijn met respectievelijk Blofeld. Tijdelijke kenmerken bieden u de flexibiliteit om allerlei aanpassingen uit te voeren en te voorkomen dat u een groot aantal ooit zo vergelijkbare fabrieken creëert.
"Normale" kenmerken in Factory Girl worden geëvalueerd wanneer de fabriek is gedefinieerd. Normaal gesproken levert u statische waarden als parameters voor methoden met dezelfde naam als uw kenmerken. Als u de evaluatie wilt uitstellen tot het laatst mogelijke moment - wanneer het exemplaar wordt geïnstantieerd - moet u hun waarden via een codeblok invoeren. Koppelingen en dynamisch gecreëerde waarden van objecten zoals Datum Tijd
objecten zullen uw meest frequente klanten zijn voor die luie behandeling.
FactoryGirl.define do factory: exploding_device do transient do countdown_seconds 10 * 60 time_of_explosion Time.now + countdown_seconds end time_of_explosion "Exploderen in # countdown_seconds seconden # time_of_explosion.strftime (" at% I:% M% p ") " end end ticking_device = create (: exploding_device) ticking_device.time_of_explosion # =>" Exploderen in 600 seconden om 11:53 PM "
Dit is waarschijnlijk geen gebruiksgeval waar je elke dag tegen aanloopt, maar soms ervaar je fabrieken van andere ontwikkelaars en je wilt ze veranderen, bijvoorbeeld als je een TDD-edelsteen gebruikt. Als u de behoefte voelt om deze legacy-fabrieken aan te passen aan uw specifieke testscenario's, kunt u deze wijzigen zonder nieuwe te maken of overerving te gebruiken.
Je doet dit via FactoryGirl.modify
, en het moet buiten dat specifieke zijn FactoryGirl.define
blokkeren dat u wilt wijzigen. Wat je niet kunt doen, is wijzigen volgorde
of trek
-u kunt kenmerken overschrijven die zijn gedefinieerd via trek
though. Terugbelacties in de "originele" fabriek zullen ook niet worden opgeheven. De terugroepactie in uw Factory.modify
blok wordt gewoon als volgende in de rij uitgevoerd.
FactoryGirl.define doen fabriek: spion do naam 'Marty McSpy' vaardigheden 'Spionage en infiltratie' deployment_status 'Voorbereiding missie' end-end FactoryGirl.modify doe reeks: mission_deployment do | nummer | "Mission # number at # DateTime.now.to_formatted_s (: short)" end factory: spy do name 'James Bond' skills 'CQC en poker' favorite_sweapon 'Walther PPK' body_count 'Classified' favorite_car 'Aston Martin DB9 'deployment generate (: mission_deployment) end end
In het bovenstaande voorbeeld hadden we onze spionnen nodig om een beetje 'geavanceerder' te zijn en een beter mechanisme te gebruiken voor de implementatie. Ik heb voorbeelden gezien waarin edelsteenauteurs anders met de tijd te maken hadden en waar het handig was om fabrieksobjecten te wijzigen door simpelweg dingen te overschrijven die je moet aanpassen.
Met callbacks kun je op verschillende momenten in de levenscyclus van een object-achtige code een aantal code injecteren opslaan
, after_save
, before_validation
enzovoorts. Rails biedt een groot aantal van hen en maakt het vrij gemakkelijk voor beginners om deze kracht te misbruiken.
Houd er rekening mee dat callbacks die geen verband houden met de persistentie van objecten een bekend antipatroon zijn en het is een goed advies om die lijn niet te overschrijden. Het lijkt bijvoorbeeld handig om een callback te gebruiken na het instantiëren van zoiets als een gebruiker om e-mails te verzenden of een order te verwerken, maar dit soort dingen nodigen bugs uit en creëren banden die onnodig moeilijk te refactiveren zijn. Misschien was dat een van de redenen waarom Factory Girl "slechts" u vijf callback-opties biedt om mee te spelen:
vóór (: te maken)
voert een codeblok uit voordat uw fabrieksinstantie wordt opgeslagen. Geactiveerd wanneer u gebruikt te maken (: some_object)
.na (: te maken)
voert een codeblok uit nadat uw fabrieksinstantie is opgeslagen. Geactiveerd wanneer u gebruikt te maken (: some_object)
.na (: build)
voert een codeblok uit nadat uw fabrieksobject in het geheugen is gebouwd. Geactiveerd wanneer u beide gebruikt bouwen (: some_object)
en te maken (: some_object)
.Na (: stub)
voert een codeblok uit nadat uw fabriek een uitgewerkt object heeft gemaakt. Geactiveerd wanneer u gebruikt build_stubbed (: some_object)
.op maat (: your_custom_callback)
voert een aangepaste terugbelfunctie uit zonder vooraf te hoeven nemen voor
of na
.FactoryGirl.define doen fabriek: missie doen objectief 'De slechte kerel stoppen' provided_gadgets 'Mini onderzeeër en haaiengeweer' after (: build) assign_support_analyst end end
Merk op dat voor alle callback-opties, binnen de callback-blokken, u via een blokparameter toegang hebt tot een exemplaar van de fabriek. Dit komt af en toe van pas, vooral met associaties.
FactoryGirl.define doen fabriek: double_agent doen na (: stomp) | double_agent | assign_new_identity (double_agent) end end
Hieronder heeft een Ninja een stel vervelende werpsterren (shuriken) tot zijn beschikking. Omdat je een hebt ninja
object in de callback, kunt u de werpster eenvoudig toewijzen aan de Ninja. Neem een kijkje op het gedeelte over verenigingen als dat voorbeeld u een paar vraagtekens laat.
FactoryGirl.define do factory: ninja do name "Ra's al Ghul" factory: ninja_with_shuriken do transient do number_of_shuriken 10 end after (: create) do | ninja, evaluator | create_list (: shuriken, evaluator.number_of_shuriken, ninja: ninja) end end end factory: shuriken do name 'Hira-shuriken' number_of_spikes 'Four' ninja end-end ninja = create (: ninja) ninja.shurikens.length # => 0 ninja = create (: ninja_with_shuriken) ninja.shurikens.length # => 10 ninja = create (: ninja_with_shuriken, number_of_shuriken: 20) ninja.shurikens.length # => 20
Via het evaluatieobject hebt u ook toegang tot voorbijgaande kenmerken. Dat geeft u de mogelijkheid om aanvullende informatie door te geven wanneer u fabrieksobjecten "creëert" en deze tijdens de vlucht moet aanpassen. Dat geeft je alle flexibiliteit die nodig is om met associaties te spelen en expressieve testgegevens te schrijven.
Als u vindt dat meerdere fabrieken meerdere keren moeten worden teruggebeld, staat Factory Girl niet in de weg, zelfs niet meerdere typen. Uiteraard is de volgorde van uitvoering van boven naar beneden.
FactoryGirl.define doen fabriek: handelaar noemt 'Mr. Hinx 'na (: create) | volgeling | henchman.send_on_kill_mission after (: create) send_cleaner end end
FactoryGirl.define do factory: bond_girl do name 'Lucia Sciarra' after (: build) | bond_girl | bond_girl.hide_secret_documents na (: create) close_hidden_safe_compartment end end
De duivel zit natuurlijk in de details. Als je gebruikt te maken (: some_object)
, beide na (: build)
en na (: te maken)
callbacks worden uitgevoerd.
Meerdere buildstrategieën kunnen worden gebundeld om dezelfde callback ook uit te voeren.
FactoryGirl.define do factory: spy do name 'Marty McFly' after (: stub,: build) | spy | spy.assign_new_mission einde
Last but not least, je kunt zelfs zoiets als "globale" callbacks instellen die callbacks voor alle fabrieken opheffen-tenminste in dat specifieke bestand als je ze hebt gescheiden in meerdere fabrieksbestanden.
fabrieken / gun.rb
FactoryGirl.define doen eerder (: stub,: build,: create) | object | object.assign_serial_number fabriek: spy_gun do name 'Walther PPK' ammunition '7.65mm Browning' association: owner factory: golden_gun do name 'Custom Lazar' ammunition '24 -carat gold bullet 'after (: create) | golden_gun | golden_gun.erase_serial_number einde end end
Als u overerving gebruikt om kinderfabrieken samen te stellen, worden de callbacks van de ouder ook overgenomen.
Laten we het allemaal samen brengen in de volgende secties over verenigingen en eigenschappen-ja, ik ben ook binnensluipen alias omdat het de beste plaats was zonder overal over te springen. Als je aandacht hebt geschonken en dingen uit het eerste artikel hebt onthouden, zou alles nu netjes op zijn plaats moeten vallen.
Associaties zijn essentieel voor elke zichzelf respecterende web-app die een beetje complex is. Een bericht dat toebehoort aan een gebruiker, een vermelding met veel beoordelingen enzovoort, zijn de ontwikkelaars van brood en boter elke dag van de week voor het ontbijt. Vanuit dat perspectief gezien, wordt het duidelijk dat fabrieken voor meer complexe scenario's kogelvrij en gemakkelijk te gebruiken moeten zijn - tenminste om niet te rotzooien met je TDD-mojo.
Modelverenigingen emuleren via Factory Girl is relatief eenvoudig, zou ik zeggen. Dat op zichzelf is best verbazingwekkend in mijn gedachten. Het bereiken van een hoog niveau van gemak en gemak voor het bouwen van complexe datasets maakt de praktijk van TDD een no-brainer en zo veel effectiever.
De nieuwe Q heeft hackervaardigheden en moet een fatsoenlijke computer bezitten, toch? In dit geval hebt u een Computer
klasse en de instanties ervan behoren tot exemplaren van de Kwartiermeester
klasse. Makkelijk, toch?
FactoryGirl.define doen fabriek: kwartiermeester do naam 'Q' vaardigheden 'dingen uitvinden' fabriek af: computer do model 'Custom Lenovo ThinkPad W Series' kwartiermeester einde
Hoe zit het met iets meer betrokken? Laten we zeggen dat onze spionnen een a gebruiken geweer
dat heeft veel cartridges
(Kogels).
klasse cartridge < ActiveRecord::Base belongs_to :gun end class Gun < ActiveRecord::Base has_many :cartridges end
FactoryGirl.define doen fabriek: cartridge doen calibre '7.65' pistool einde fabriek: pistool do naam 'Walther PPK' munitie '7.65mm Browning' kaliber '7.65' fabriek: gun_with_ammo doen transient doen magazine_size 10 einde na (: create) do | gun , evaluator | create_list (: cartridge, evaluator.magazine_size, gun: gun) end end end end
Terugbellen komt best wel goed met associaties, toch? Nu kun je een pistool bouwen met of zonder munitie. Via de hash pistool: pistool
jij hebt het patroon
fabriek met de nodige informatie om de associatie via de vreemde sleutel
.
spy_gun = create (: gun) spy_gun.cartridges.length # => 0 spy_gun_with_ammo = create (: gun_with_ammo) spy_gun_with_ammo.cartridges.length # => 10
Als u nog een tijdschriftformaat nodig heeft, kunt u deze doorgeven via uw tijdelijk kenmerk.
big_magazine_gun = create (: gun_with_ammo, magazine_size: 20) big_magazine_gun.cartridges.length # => 20
Dus hoe zit het met de verschillende build-strategieën? Was er niet iets raars? Nou, hier is wat je moet onthouden: als je gebruikt creëren
voor gekoppelde objecten worden beide opgeslagen. Zo te maken (: kwartiermaker)
zal zowel Q als zijn ThinkPad bouwen en opslaan.
Ik kan het beter gebruiken bouwen
, dan, als ik wil vermijden om de database te raken, toch? Goed idee, maar bouwen
zou alleen van toepassing zijn op kwartiermeester
in ons voorbeeld - de bijbehorende computer
zou nog steeds worden opgeslagen. Een beetje lastig, ik weet het. Dit is wat u kunt doen als u het bijbehorende object niet hoeft op te slaan - u geeft de buildstrategie op die u nodig heeft voor uw associatie.
FactoryGirl.define do factory: kwartiermeester do name 'Q' skills 'Inventing stuff' end factory: computer do model 'Custom Lenovo ThinkPad W Series' associatie: kwartiermeester, strategie:: build end end
U noemt het bijbehorende fabrieksobject en geeft een hash door met uw bouwstrategie. U moet het expliciete gebruiken vereniging vraag dit om te werken. Het onderstaande voorbeeld zal niet werken.
fabriek: computer model 'Custom Lenovo ThinkPad W Series' kwartteller, strategie:: einde bouwen
Nu gebruiken beide objecten bouwen
en niets wordt opgeslagen in de database. We kunnen die aanname controleren met behulp van nieuw record?
, welke terugkeert waar
als het exemplaar niet is behouden.
thinkpad = build (: computer) thinkpad.new_record? # => true thinkpad.quartermaster.new_record? # => waar
Terwijl we bezig zijn, via het expliciete vereniging bel kunt u ook meteen verwijzen naar verschillende fabrieksnamen en attributen wijzigen.
FactoryGirl.define do factory: kwartiermeester do name 'Q' end factory: computer do model 'Custom Lenovo ThinkPad W Series' associatie: hacker, fabriek:: kwartiermaker, vaardigheden: 'Hacking' end-end
Laten we dit hoofdstuk afsluiten met een voorbeeld dat dat is polymorfe.
klasse Spion < 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 do factory: mifive do name 'Military Intelligence, Section 5' principal_activity 'Domestic contra-intelligence' end factory: misix do name 'Military Intelligence, Section 6' principal_activity 'Foreign contra-intelligence' end factory: mifive_spy, klasse: Spy do name '005' associatie: spyable, factory:: mifive end factory: misix_spy, class: Spy do name '006' association: spyable, factory:: misix end end # MI5 agents mifive = create (: mifive) mifive_spy = create (: 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 agents misix = create (: misix) misix_spy_01 = create (: misix_spy, name: '007') misix_spy_02 = create (: 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'
Voel je niet slecht als dit iets meer tijd nodig heeft om in te zakken. Ik raad aan Polymorphic-verenigingen in te halen als je niet zeker weet wat hier gebeurt.
Aliassen voor uw fabrieken stellen u in staat om expressiever te zijn over de context waarin u uw fabrieksobjecten gebruikt. U hoeft alleen een hash van alternatieve namen op te geven die de relatie tussen gekoppelde objecten beter beschrijven.
Laten we zeggen dat je een hebt :middel
fabriek en een : law_enforcement_vehicle
fabriek. Zou het niet leuk zijn om naar de agent te verwijzen als :eigenaar
in de context van deze auto's? In het onderstaande voorbeeld heb ik het vergeleken met een voorbeeld zonder een alias.
FactoryGirl.define do factory: agent, aliassen: [: owner] do name 'Fox Mulder' job 'Chasing bad dudes' special_skills 'Investigation and intelligence' factory: double_O_seven do name 'James Bond' end-end fabriek: law_enforcement_vehicle do name 'Oldsmobile Achieva 'vriendelijke' compacte auto ': eigenaar-eindfabriek: spy_car do noem' Aston Martin DB9 'soort' sportwagen 'double_O_seven einde
Vergeet niet om een dubbele punt toe te voegen voor de gealiaste fabriek (:eigenaar
) wanneer u ze gebruikt voor verenigingen in uw fabrieken. De documentatie en veel blogberichten gebruiken ze in deze gevallen zonder dubbele punten. Alles wat je krijgt is waarschijnlijk een NoMethodError
omdat je nu een setter-methode mist voor die alias. (Ik kan beter een pull-aanvraag openen.) De eerste keer dat ik dit tegenkwam, verbijsterde het me en nam me een beetje om er voorbij te komen. Vergeet niet om documentatie en blogberichten soms selectief te wantrouwen. Met vriendelijke groeten, natuurlijk.
Ik denk dat je het ermee eens zult zijn dat het gebruik van aliassen niet alleen beter is, maar ook jou of de persoon die na je komt een beetje meer context geeft over de objecten in kwestie. Ja, je moet meervoud gebruiken : aliassen
ook als je maar één alias hebt.
Je zou dit ook een beetje anders kunnen schrijven - veel meer verbaal.
fabriek: agent, aliassen: [: mulder] do name 'Fox Mulder' job 'Chasing bad dudes' special_skills 'Investigation and intelligence' end factory: law_enforcement_vehicle do name 'Oldsmobile Achieva' soort 'Compact car' vereniging: eigenaar, fabriek: agent einde
Nou, niet zo netjes, is het?
Natuurlijk kunt u deze aliassen ook gebruiken om fabrieksobjecten meteen te "bouwen".
fbi_agent = create (: mulder) fbi_agent.name # => 'Fox Mulder'
In de context van opmerkingen, a :gebruiker
zou kunnen worden aangeduid als : commenter
, in het geval van een :misdrijf
een :gebruiker
zou kunnen worden gealiast als een :verdachte
, enzovoorts. Het is geen echte rocket science-like zoals syntactische suiker die je verleiding voor duplicatie vermindert.
Dit is een van mijn favoriete dingen over Factory Girl. Kort samengevat: kenmerken zijn lego-achtige blokken om uw fabrieken te bouwen en gedrag te combineren. Het zijn door komma's gescheiden lijsten met symbooleigenschappen / kenmerken die u aan een bepaalde fabriek wilt toevoegen, en ze worden ook gedefinieerd in de bestanden van uw bedrijf (s).
In mijn gedachten, trek
is de krachtigste en handigste functie om uw fabrieksgegevens te DROGEN terwijl ze tegelijkertijd expressief zijn. Hiermee kunt u groepen attributen bij elkaar bundelen, afzonderlijke namen geven en deze waar en wanneer u maar wilt opnieuw gebruiken. Weet je nog toen ik je aanmaaide om kale fabrieksobjecten te definiëren? Met eigenschappen kunt u precies dat bereiken zonder in te boeten aan gebruiksgemak.
FactoryGirl.define do factory: spy_car model 'Aston Martin DB9' top_speed '295 km / h' build_date '2015' ejection_seat true trait: submarine do ejection_seat false water_resistant '100 m' submarine_capabilities true air_independent_propulsion true end trait: weaponized do rockets true number_of_rockets '12' machine_gun true fliesof_fire '1.500 RPM' tank_armour true end eigenschap: cloaked do active_camouflage true radar_signature 'reduced' engine 'silenced' end trait: night_vision do infrared_sensors true heads_up_display true end end end
Zoals u kunt zien, kunt u sommige attributen die over meerdere objecten zijn verspreid, nu op één centrale plaats doen. Geen operatie van het geweer nodig. Staatssturing via eigenschappen zou niet handiger zijn.
Met die opstelling kun je behoorlijk uitgebreide spionnenauto's bouwen door de verschillende attribuutbundels te mengen zoals je maar wilt, zonder iets te dupliceren door allerlei nieuwe fabrieken te maken die alle verschillende opties die je nodig hebt, hebben..
invisible_spy_car = create (: spy_car,: cloaked,: night_vision) diving_spy_car = create (: spy_car,: submarine,: cloaked) tank_spy_car = create (: spy_car,: weaponized,: night_vision)
Je kunt eigenschappen gebruiken met creëren
, bouwen
, build_stubbed
en attributes_for
. Als Q slim wordt, kun je individuele attributen tegelijkertijd vervangen door een hash in te voeren.
build (: spy_car,: submarine, ejection_seat: true)
Voor kenmerkcombinaties die heel vaak voorkomen in een bepaalde fabriek, kunt u ook kinderfabrieken maken met namen die de verschillende combinaties van gegevensverzamelingen het best weergeven. Op die manier bundelt u hun eigenschappen slechts eenmaal, in tegenstelling tot de hele tijd dat u testgegevens maakt.
FactoryGir.define do factory: spy_car model 'Aston Martin DB9' top_speed '295 km / h' build_date '2015' ejection_seat true trait: submarine do ... end trait: weaponized do ... end trait: cloaked do ... end trait: night_vision do ... end-end fabriek: invisible_spy_car, eigenschappen: [: cloaked,: night_vision] fabriek: diving_spy_car, eigenschappen: [: submarine,: cloaked] factory: tank_spy_car, traits: [: weaponized,: night_vision] factory: ultimate_spy_car, traits: [: cloaked ,: night_vision,: submarine,: weaponized] end
Hiermee kunt u deze objecten veel bondiger maken en is deze ook beter leesbaar.
build_stubbed (: invisible_spy_car) create (: ultimate_spy_car)
In plaats van:
build_stubbed (: spy_car,: cloaked,: night_vision) create (: spy_car,: cloaked,: night_vision,: submarine,: weaponized)
Leest veel beter, niet? Vooral als er geen variabele namen bij betrokken zijn.
Je kunt zelfs eigenschappen hergebruiken als attributen op andere eigenschappen en fabrieken. Als u dezelfde kenmerken voor meerdere kenmerken definieert, krijgt de laatst gedefinieerde eigenschap uiteraard voorrang.
FactoryGirl.define do factory: spy_car model 'Aston Martin DB9' top_speed '295 km / h' build_date '2015' ejection_seat true trait: submarine do ... end trait: weaponized do ... end trait: cloaked do ... end trait: night_vision do ... eind eigenschap: mobile_surveillance do cloaked night_vision signal_detector true signal_analyzer true wifi_war_driver true license_plate_reader true mini_drone true end end fabriek: ultimate_spy_car, ouder:: spy_car do car_plane echt onderzeeër bewapend eind van mobiele bewaking
Let op de mobile_surveillance
eigenschap, die het gehuld
en nachtzicht
eigenschappen - fundamenteel als een attribuut. Ook de ultimate_spy_car
fabriek, die ik uit de spy_car
fabrieksdefinitie voor de lol deze keer, hergebruikt alle eigenschappen plus een extra attribuut dat het ook laat vliegen. Pure filmmagie - of misschien moet ik Factory Girl-magie noemen.
create_list
en build_list
kan ook gebruik maken van eigenschappen. De tweede parameter moet het aantal fabrieksinstanties zijn dat u wilt.
create_list (: spy_car, 3,: night_vision) build_list (: spy_car, 4,: submarine,: cloaked)
Zou het niet cool zijn om associaties met eigenschappen te gebruiken? Natuurlijk kunt u callbacks en verenigingen netjes in kenmerken opnemen. duh!
FactoryGirl.define do factory: cartridge do kind 'Kleine calliber pistool ammunitie' calibre '7.65' projectiel 'Lead' pistool fabriek: golden_cartridge do projectile 'Gouden' associatie: pistool,: gouden end-end fabriek: pistool do naam 'Walther PPK' munitie '7.65mm Browning' calibre '7.65' transient do magazine_size 10 end eigenschap: golden do name 'Custom Lazar' ammunition '23 -carat gold bullet 'end trait: with_ammo do after (: create) do | gun, evaluator | create_list (: cartridge, evaluator.magazine_size, gun: gun) end-end eigenschap: with_golden_ammo do after (: create) do | golden_gun, evaluator | create_list (: golden_cartridge, evaluator.magazine_size, gun: golden_gun) end end end end
Hoe ze te gebruiken zou nu saai moeten zijn.
cartridge = create (: cartridge) cartridge.projectile # => 'Lead' cartridge.gun.name # => 'Walther PPK' cartridge.gun.ammunition # => '7.65mm Browning' cartridge.gun.caliber # => ' 7.65 'golden_cartridge = create (: golden_cartridge) golden_cartridge.projectile # =>' Gold 'golden_cartridge.gun.name # =>' Custom Lazar 'golden_cartridge.gun.ammunition # => '23 -carat gold bullet' golden_cartridge.gun.caliber # => '7.65' gun_with_ammo = create (: gun,: with_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 = create (: gun,: golden,: with_golden_ammo) golden_gun_with_golden_ammo.name # => 'Custom Lazar' golden_gun_with_golden_ammo.ammunition # = > '24 -carat gold bullet 'golden_gun_with_golden_ammo.cartridges.length # => 10 golden_gun_with_golden_ammo.cartridges.first.projectile # =>' Goud ' golden_gun_with_golden_ammo.cartridges.first.caliber # => '7.65'
Laatste woorden van wijsheid: Verandering is je constante metgezel-moeten veranderen attributen of datatypes gebeurt de hele tijd. Ontwerpbeslissingen zoals deze evolueren. Met eigenschappen kunt u de pijn daarmee verlichten en kunt u uw gegevenssets beheren.
Stel je voor dat je een optie-hash hebt gebruikt voor instantiatie en dat die vereiste volledig is veranderd. Hoeveel potentiële plaatsen in uw tests kunnen breken en hebben nu aandacht nodig? Rechtop, trek
is een zeer effectief hulpmiddel voor het elimineren van duplicatie in uw testsuite. Maar met al dat gemak, wees niet lui en vergeet uw unit tests op de kolommen die worden weergegeven door uw eigenschappen! Op die manier geef je ze dezelfde hoeveelheid zorg als de kale attributen die nodig zijn voor geldige objecten.
Er is iets meer te ontdekken in Factory Girl en ik ben ervan overtuigd dat je nu meer dan goed uitgerust bent om de stukken bij elkaar te brengen wanneer je ze nodig hebt. Veel plezier met het spelen van dit juweeltje. Ik hoop dat je TDD-gewoonten hiervan zullen profiteren.