diff --git a/README.markdown b/README.markdown index 5a506c8..c121b18 100644 --- a/README.markdown +++ b/README.markdown @@ -19,19 +19,16 @@ release version of Machinist, [then go with Machinist 1](http://github.com/notahat/machinist/tree/1.0-maintenance). - [Home page](http://github.com/notahat/machinist) -- [What's new in Machinist 2](http://wiki.github.com/notahat/machinist/machinist-2) -- [Installation](http://wiki.github.com/notahat/machinist/installation) -- [Documentation](http://wiki.github.com/notahat/machinist/getting-started) -- [Google group](http://groups.google.com/group/machinist-users) -- [Bug tracker](http://github.com/notahat/machinist/issues) +- [Google group](http://groups.google.com/group/machinist-users), for support +- [Bug tracker](http://github.com/notahat/machinist/issues), for Machinist bugs -# Introduction +## Introduction -Machinist makes it easy to create objects within your tests. It generates data +Machinist makes it easy to create objects for use in tests. It generates data for the attributes you don't care about, and constructs any necessary -associated objects, leaving you to specify only the attributes you *do* care -about in your tests. For example: +associated objects, leaving you to specify only the fields you care about in +your test. For example: describe Comment do it "should not include spam in the without_spam scope" do @@ -43,6 +40,7 @@ about in your tests. For example: end end + You tell Machinist how to do this with blueprints: require 'machinist/active_record' @@ -50,7 +48,7 @@ You tell Machinist how to do this with blueprints: User.blueprint do username { "user#{sn}" } # Each user gets a unique serial number. end - + Post.blueprint do author title { "Post #{sn}" } @@ -59,13 +57,195 @@ You tell Machinist how to do this with blueprints: Comment.blueprint do post - email { "commenter-#{sn}@example.com" } + email { "commenter#{sn}@example.com" } body { "Lorem ipsum..." } end -Check out the -[documentation](http://wiki.github.com/notahat/machinist/getting-started) for -more info. + +## Installation + +### Upgrading from Machinist 1 + +See [the wiki](http://wiki.github.com/notahat/machinist/machinist-2) + +### Rails 3 + +In your app's `Gemfile`, in the `group :test` section, add: + + gem 'machinist', '>= 2.0.0.beta2' + +Then run: + + bundle + rails generate machinist:install + +If you want Machinist to automatically add a blueprint to your blueprints file +whenever you generate a model, add the following to your +`config/application.rb` in the `config.generators` section: + + g.fixture_replacement :machinist + + +### Rails 2 + +See [the wiki](http://wiki.github.com/notahat/machinist/rails-2) + + +## Usage + +### Blueprints + +A blueprint describes how to generate an object. The idea is that you let the +blueprint take care of making up values for attributes that you don't care +about in your test, leaving you to focus on the just the things that you're +testing. + +A simple blueprint might look like this: + + Post.blueprint do + title { "Post #{sn}" } + body { "Lorem ipsum..." } + end + +You can then construct a Post from this blueprint with: + + Post.make! + +When you call `make!`, Machinist calls `Post.new`, then runs through the +attributes in your blueprint, calling the block for each attribute to generate +a value. It then saves and reloads the Post. (It throws an exception if the +Post can't be saved.) + +For attributes that need to be unique, you can call the `sn` method from +within the attribute block to get a unique serial number for the object. + +You can override values defined in the blueprint by passing a hash to make: + + Post.make!(:title => "A Specific Title") + +If you want to generate an object without saving it to the database, replace +`make!` with `make`. + +You can refer to already assigned attributes when constructing a new attribute: + + Post.blueprint do + author { "Fred Author" } + body { "Post by #{object.author}" } + end + + +### Named Blueprints + +Named blueprints let you define variations on an object. For example, suppose +some of your Users are administrators: + + User.blueprint do + name { "User #{sn}" } + email { "user-#{sn}@example.com" } + end + + User.blueprint(:admin) do + name { "Admin User #{sn}" } + admin { true } + end + +Calling: + + User.make!(:admin) + +will use the `:admin` blueprint. + +Named blueprints call the default blueprint to set any attributes not +specifically provided, so in this example the `email` attribute will still be +generated even for an admin user. + +You must define a default blueprint for any class that has a named blueprint, +even if the default blueprint is empty. + + +### Associations + +If your object needs associated objects, you can generate them like this: + + Comment.blueprint do + post { Post.make } + end + +Calling `Comment.make!` will construct a Comment and its associated Post, and +save both. + +If you want to override the value for post when constructing the comment, you +can do this: + + post = Post.make(:title => "A particular title) + comment = Comment.make(:post => post) + +Machinist is smart enough to look at the association and work out what sort of +object it needs to create, so you can shorten the above blueprint to: + + Comment.blueprint do + post + end + +For `has_many` and `has_and_belongs_to_many` associations, you can create +multiple associated objects like this: + + Post.blueprint do + comments(3) + end + + +### Blueprints on Plain Old Ruby Objects + +Machinist also works with plain old Ruby objects. Let's say you have a class like: + + class Post + extend Machinist::Machinable + + attr_accessor :title + attr_accessor :body + end + +You can blueprint the Post class just like anything else: + + Post.blueprint do + title { "A title!" } + body { "A body!" } + end + +And `Post.make` will construct a new Post. + + +## Compatibility + +I've tested this with: + +Ruby versions: 1.8.7, 1.9.2 +Rails versions: 2.3, 3.0, 3.1 + +It may well be happy with other versions too, but I'm not promising anything. +Compatibility patches are welcome. + + +## Developing + +The Machinist specs and source code were written to be read, and I'm pretty +happy with them. Don't be have a look under the hood. + +- Fork the project. +- Make your feature addition or bug fix. +- Add tests for it. This is important so I don't break it in a + future version unintentionally. +- Commit, do not mess with rakefile, version, or history. + (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) +- Send me a pull request. Bonus points for topic branches. + + +## Status + +In active use in a number of large Rails 2 apps. + +Development has been sporadic, but is picking up again. ## Contributors @@ -100,4 +280,4 @@ Thanks to Thoughtbot's [Factory Girl](http://github.com/thoughtbot/factory_girl/tree/master). Machinist was written because I loved the idea behind Factory Girl, but I thought the philosophy wasn't quite right, and I hated the syntax. - +