nakajima / fixjour
- Source
- Commits
- Network (8)
- Issues (1)
- Downloads (5)
- Wiki (1)
- Graphs
-
Tree:
5af8b20
fixjour / README.textile
| 54c750f5 » | nakajima | 2008-12-28 | 1 | h1. fixjour | |
| 2 | |||||
| 56bb85e2 » | nakajima | 2009-02-18 | 3 | Another fixture replacement. Gets you some methods (@new_*@, @create_*@ and | |
| 4 | @valid_*_attributes@) methods and some confidence. | ||||
| 559928f0 » | nakajima | 2008-12-28 | 5 | ||
| 25b30872 » | nakajima | 2009-03-09 | 6 | "View the RDoc":http://gitrdoc.com/nakajima/fixjour/tree/master (still underway, but has a bit of helpful stuff) | |
| 858083a2 » | nakajima | 2009-03-09 | 7 | ||
| 5af8b205 » | nakajima | 2009-06-30 | 8 | "Recommend Me on the Working with Rails":http://www.workingwithrails.com/person/7973-pat-nakajima | |
| 9 | |||||
| 807b81fc » | patmaddox | 2009-05-02 | 10 | h2. Contribute | |
| 11 | |||||
| dd5713d3 » | nakajima | 2009-05-17 | 12 | Fixjour has some developer dependencies. Install them as shown below, | |
| 13 | and run rake to make sure the tests pass. Then dive in! | ||||
| 807b81fc » | patmaddox | 2009-05-02 | 14 | ||
| 15 | <pre> | ||||
| 16 | fixjour:$ gem build fixjour.gemspec | ||||
| 17 | fixjour:$ sudo gem install --development fixjour | ||||
| 18 | fixjour:$ rake | ||||
| 19 | Do the tests pass? | ||||
| 20 | </pre> | ||||
| 877bf786 » | nakajima | 2009-01-05 | 21 | h2. The focus of this project is liberation through constraints. | |
| 22984a48 » | nakajima | 2008-12-29 | 22 | ||
| 23 | It uses the bits of object mother systems that worked well for | ||||
| 24 | me in the past, and actively discourages the bits that have caused | ||||
| 25 | me pain. | ||||
| 26 | |||||
| 9bb35205 » | nakajima | 2009-01-06 | 27 | The constraints: | |
| 877bf786 » | nakajima | 2009-01-05 | 28 | ||
| 29 | h4. One builder per model | ||||
| 30 | |||||
| 31 | If you try to define a builder more than once per model, you'll | ||||
| 32 | run into a @Fixjour::RedundantBuilder@ error. One builder per | ||||
| 33 | model decreases confusion. | ||||
| 34 | |||||
| 35 | h4. No redundant object creation methods | ||||
| 36 | |||||
| 37 | If you try to define a method that's already been defined by | ||||
| 38 | a Fixjour builder, you'll run into a @Fixjour::RedundantBuilder@ | ||||
| 39 | error. If you find the need to alter the behavior of a builder | ||||
| 40 | for a particular set of tests, you should just wrap the creation | ||||
| 41 | methods defined by Fixjour, preferably with a name that describes | ||||
| 42 | how the new method is different from the Fixjour method. | ||||
| 43 | |||||
| 44 | h4. Processing the overrides hash is bad | ||||
| 45 | |||||
| 46 | If you want to mess with the overrides hash that can be passed | ||||
| 47 | into any of the creation methods, you must use the @process@ | ||||
| 48 | method (see below). To enforce this, the @delete@ method is actually | ||||
| 49 | private for the overrides hash. | ||||
| 50 | |||||
| fdcfcbcb » | nakajima | 2008-12-29 | 51 | h2. What it gets you: | |
| fc5d4dd7 » | nakajima | 2008-12-29 | 52 | ||
| 53 | With this setup: | ||||
| 54 | |||||
| 55 | <pre> | ||||
| 56 | Fixjour do | ||||
| 2e88fa35 » | nakajima | 2009-01-08 | 57 | define_builder(Person) do |klass, overrides| | |
| 58 | klass.new(:name => 'Pat', :age => 22) | ||||
| fc5d4dd7 » | nakajima | 2008-12-29 | 59 | end | |
| 60 | end | ||||
| 61 | |||||
| 62 | include Fixjour | ||||
| 63 | </pre> | ||||
| 64 | |||||
| 65 | You get: | ||||
| 66 | |||||
| e13f3534 » | nakajima | 2008-12-29 | 67 | h3. @new_person(overrides={})@ | |
| fc5d4dd7 » | nakajima | 2008-12-29 | 68 | ||
| 69 | The @new_person@ method basically just returns the result | ||||
| 70 | of your builder block, which should *always return an unsaved | ||||
| 71 | instance of the model class*. You can pass it overrides in a | ||||
| 72 | hash like so: @new_person(:name => nil)@. | ||||
| 73 | |||||
| e13f3534 » | nakajima | 2008-12-29 | 74 | h3. @create_person(overrides={})@ | |
| fc5d4dd7 » | nakajima | 2008-12-29 | 75 | ||
| 76 | The @create_person@ method calls @new_person@, passing in any | ||||
| 77 | overrides you pass it, calls @save!@ on the result, and returns | ||||
| 78 | the saved object. | ||||
| 79 | |||||
| e13f3534 » | nakajima | 2008-12-29 | 80 | h3. @valid_person_attributes(overrides={})@ | |
| fc5d4dd7 » | nakajima | 2008-12-29 | 81 | ||
| 82 | The @valid_person_attributes@ returns a hash of valid person | ||||
| 83 | attributes that are derived from the @new_person@ method, and | ||||
| 84 | ideal for things like testing controllers. It can also take | ||||
| 85 | attribute override options like so: @valid_person_attributes(:name => nil)@. | ||||
| 86 | |||||
| fdcfcbcb » | nakajima | 2008-12-29 | 87 | h2. Usage: | |
| fc5d4dd7 » | nakajima | 2008-12-29 | 88 | ||
| 89 | You specify builder sets for your ActiveRecord models in a | ||||
| fdcfcbcb » | nakajima | 2008-12-29 | 90 | @Fixjour@ block using the @define_builder@ helper, which can | |
| 91 | be used in one of two ways: | ||||
| 92 | |||||
| 93 | h3. Using a builder block | ||||
| 94 | |||||
| 95 | Pass @define_builder@ a model class for which you want a new set | ||||
| fc5d4dd7 » | nakajima | 2008-12-29 | 96 | of creation methods, and a block which returns a new valid | |
| 2e88fa35 » | nakajima | 2009-01-08 | 97 | model object. The block will be passed two arguments: a proxy | |
| 98 | object for your class, and an overrides hash. If you call @new@ | ||||
| 99 | on the class proxy, it will return a new instance of the class, | ||||
| 100 | with whatever attributes you specify as defaults. It will also | ||||
| 101 | automatically merge any override options in all of the methods | ||||
| 102 | generated by Fixjour. | ||||
| fc5d4dd7 » | nakajima | 2008-12-29 | 103 | ||
| fdcfcbcb » | nakajima | 2008-12-29 | 104 | Example: | |
| 105 | |||||
| 106 | <pre> | ||||
| 2e88fa35 » | nakajima | 2009-01-08 | 107 | define_builder(Person) do |klass, overrides| | |
| 108 | klass.new(:name => "Pat", :age => 22) | ||||
| fdcfcbcb » | nakajima | 2008-12-29 | 109 | end | |
| 110 | </pre> | ||||
| 111 | |||||
| 98818d7c » | Pat Nakajima & Mike Dalessio | 2009-01-05 | 112 | If you want to process an option in the overrides hash, you can use | |
| 113 | the @process@ method: | ||||
| 114 | |||||
| 115 | <pre> | ||||
| 2e88fa35 » | nakajima | 2009-01-08 | 116 | define_builder(Person) do |klass, overrides| | |
| 98818d7c » | Pat Nakajima & Mike Dalessio | 2009-01-05 | 117 | overrides.process(:child) do |is_child| | |
| 118 | overrides[:age] = 14 if is_child | ||||
| 119 | end | ||||
| 120 | |||||
| 2e88fa35 » | nakajima | 2009-01-08 | 121 | klass.new(:name => "Pat", :age => 22) | |
| 98818d7c » | Pat Nakajima & Mike Dalessio | 2009-01-05 | 122 | end | |
| 123 | |||||
| fa1c235d » | nakajima | 2009-01-05 | 124 | # the default | |
| 125 | person = new_person | ||||
| 126 | person.age # => 22 | ||||
| 127 | |||||
| 128 | # using the override | ||||
| 98818d7c » | Pat Nakajima & Mike Dalessio | 2009-01-05 | 129 | person = new_person(:child => true) | |
| 130 | person.age # => 14 | ||||
| 131 | </pre> | ||||
| 132 | |||||
| 133 | In the above example, the @:child@ key will be deleted from the @overrides@ | ||||
| 134 | hash and made available as the @is_child@ block argument where you can handle | ||||
| 135 | things accordingly. | ||||
| 136 | |||||
| c262943b » | nakajima | 2009-01-05 | 137 | *Note:* The @delete@ method is private on the overrides hash passed into the | |
| 138 | builder block. This is meant to encourage you to only use the @process@ method | ||||
| 139 | instead. Why? First, because processing the overrides hash is a smell. Deal | ||||
| 140 | with it. Second, using the @process@ method provides some indication to readers | ||||
| 141 | that you're screwing with the overrides hash, and that's a good thing. | ||||
| 142 | |||||
| be861d7c » | nakajima | 2009-02-08 | 143 | h4. @attr_protected@ fields | |
| 144 | |||||
| 145 | If you have fields that cannot be mass-assigned, use the @protected@ helper: | ||||
| 146 | |||||
| 147 | define_builder(Article) do |klass, overrides| | ||||
| 148 | klass.protected :author | ||||
| 149 | klass.new :title => "The title", :body => "good", :author => new_user | ||||
| 150 | end | ||||
| 151 | |||||
| 152 | If you use the @protected@ helper to declare @attr_protected@ fields, you can | ||||
| 153 | then treat them the same as any other field in your test methods. | ||||
| 154 | |||||
| fc5d4dd7 » | nakajima | 2008-12-29 | 155 | h4. With Associations | |
| 156 | |||||
| c9d1391c » | nakajima | 2008-12-29 | 157 | To specify an associated object, you can call that object's @new_*@ method: | |
| fc5d4dd7 » | nakajima | 2008-12-29 | 158 | ||
| 159 | <pre> | ||||
| 160 | Fixjour do | ||||
| 2e88fa35 » | nakajima | 2009-01-08 | 161 | define_builder(Post) do |klass, overrides| | |
| 162 | klass.new(:name => 'a post', :body => 'texted') | ||||
| fc5d4dd7 » | nakajima | 2008-12-29 | 163 | end | |
| 164 | |||||
| 2e88fa35 » | nakajima | 2009-01-08 | 165 | define_builder(Comment) do |klass, overrides| | |
| 166 | klass.new(:body => 'Oh ok!', :post => new_post) | ||||
| fc5d4dd7 » | nakajima | 2008-12-29 | 167 | end | |
| 168 | end | ||||
| 169 | |||||
| 170 | include Fixjour | ||||
| 171 | |||||
| 172 | new_comment.post.name # => 'a post' | ||||
| 173 | </pre> | ||||
| 559928f0 » | nakajima | 2008-12-28 | 174 | ||
| c9d1391c » | nakajima | 2008-12-29 | 175 | Note that it's never a good idea to use a @create_*@ method in a | |
| 176 | build block. | ||||
| 177 | |||||
| 4936e174 » | nakajima | 2008-12-29 | 178 | h3. Verifying your setups | |
| 179 | |||||
| 180 | Fixjour requires more work on your part, so it also includes a way | ||||
| 181 | to verify that your creation methods are behaving the way they should. | ||||
| 182 | Call @Fixjour.verify!@ to ensure the following things: | ||||
| 183 | |||||
| 184 | # Creation methods are returning valid objects by default. | ||||
| 185 | # @new_*@ methods are returning new records. | ||||
| 186 | # @new_*@ and @create_*@ methods return instances of the correct class. | ||||
| 187 | |||||
| ed7ea2e8 » | bmabey | 2009-02-05 | 188 | h3. Recommended usage with RSpec and Cucumber | |
| 189 | |||||
| dd5713d3 » | nakajima | 2009-05-17 | 190 | If you want to use Fixjour with RSpec and Cucumber you probably want to avoid adding the builder methods onto Object directly. To do this you should first create a file where your Fixjour builder definitions can live. Say for example you put it at spec/fixjour_builders.rb. To take advantage of these builders from RSpec use the following code in your spec_helper.rb: | |
| ed7ea2e8 » | bmabey | 2009-02-05 | 191 | ||
| 192 | <pre> | ||||
| 193 | require File.expand_path(File.dirname(__FILE__) + "/fixjour_builders.rb") | ||||
| 194 | |||||
| 195 | Spec::Runner.configure do |config| | ||||
| 196 | config.include(Fixjour) # This will add the builder methods to your ExampleGroups and not pollute Object | ||||
| 197 | ... | ||||
| 198 | end | ||||
| 199 | </pre> | ||||
| 200 | |||||
| feb00942 » | olauzon | 2009-04-15 | 201 | To use the same builders in Cucumber you simply need to include Fixjour into your World object from features/support/env.rb: | |
| ed7ea2e8 » | bmabey | 2009-02-05 | 202 | ||
| 203 | <pre> | ||||
| 204 | require File.expand_path(File.dirname(__FILE__) +'/../../spec/fixjour_builders.rb') | ||||
| 205 | World { |world| world.extend(Fixjour) } | ||||
| 206 | </pre> | ||||
| 207 | |||||
| dd5713d3 » | nakajima | 2009-05-17 | 208 | Be sure to do this after you define your World object. So, if you are using Rails you should include Fixjour after you require 'cucumber/rails/world'. | |
| ed7ea2e8 » | bmabey | 2009-02-05 | 209 | ||
| feb00942 » | olauzon | 2009-04-15 | 210 | In *Cucumber version 0.2.3.2 and later* you need to pass in a module to the World method to extend it: | |
| 211 | |||||
| 212 | <pre> | ||||
| 213 | require File.expand_path(File.dirname(__FILE__) +'/../../spec/fixjour_builders.rb') | ||||
| 214 | World(Fixjour) | ||||
| 215 | </pre> | ||||
| 216 | |||||
| 217 | (See the Cucumber::StepMother#World RDoc or "http://wiki.github.com/aslakhellesoy/cucumber/a-whole-new-world":http://wiki.github.com/aslakhellesoy/cucumber/a-whole-new-world.) | ||||
| 218 | |||||
| c823c9e0 » | nakajima | 2009-02-10 | 219 | h4. Contributors | |
| 220 | |||||
| 221 | * "Pat Maddox":http://github.com/pat-maddox - Sparked the original idea and fixed my bugs | ||||
| 222 | * "Ben Mabey":http://github.com/bmabey - Added docs and fixed my bugs | ||||
| 223 | * "Aaron Quint":http://github.com/quirkey - Pointed out valid attrs problem and fixed my bugs | ||||
| 224 | |||||
| 527c21c0 » | nakajima | 2008-12-29 | 225 | h4. TODO | |
| 226 | |||||
| 2e1095fc » | nakajima | 2009-01-30 | 227 | * There should be a @Builder@ class. | |
| 527c21c0 » | nakajima | 2008-12-29 | 228 | ||
| b9591c60 » | nakajima | 2009-02-22 | 229 | h4. "Join the mailing list.":http://groups.google.com/group/fixjour | |
| 527c21c0 » | nakajima | 2008-12-29 | 230 | ||
| 85c401f8 » | nakajima | 2008-12-29 | 231 | I've talked to smart people who like these instead: | |
| 232 | |||||
| 233 | * "fixturereplacement":http://github.com/smtlaissezfaire/fixturereplacement/tree/master | ||||
| 234 | * "factory girl":http://github.com/thoughtbot/factory_girl/tree | ||||
| 235 | |||||
| ed7ea2e8 » | bmabey | 2009-02-05 | 236 | (c) Copyright 2008 Pat Nakajima, released under MIT License. | |


