RSpec Approvals
Approvals are based on the idea of the golden master.
You take a snapshot of an object, and then compare all future versions of the object to the snapshot.
Big hat tip to Llewellyn Falco who developed the approvals concept, as well as the original approvals libraries (.NET, Java, Ruby, PHP, probably others).
See ApprovalTests for videos and additional documentation about the general concept.
Also, check out Herding Code's podcast #117 http://t.co/GLn88R5 in which Llewellyn Falco is interviewed about approvals.
Configuration
The default location for the output files is
spec/approvals
You can change this using the configuration option
RSpec.configure do |c|
c.approvals_path = 'some/other/path'
end
Usage
The basic format of the approval is modeled after RSpec's it
:
verify "something" do
"this is the received contents"
end
The :inspect
method on the object will be used to generate the output for
the *.received.txt
file. For custom objects you will need to override
the :inspect
to get helpful output, rather than the default:
#<Object:0x0000010105ea40> # or whatever the object id is
The first time the specs are run, two files will be created:
full_description_of_something.received.txt
full_description_of_something.approved.txt
Since you have not yet approved anything, the *.approved.txt
file is
empty.
The contents of the two files are compared, and the approval will fail at this point.
Formatting
You can pass options to format output before it gets written to the file. At the moment, only xml, html, and json are supported.
Simply add a :format => :xml
, :format => :html
, or :format => :json
option to the example:
verify "some html", :format => :html do
"<html><head></head><body><h1>ZOMG</h1></body></html>"
end
verify "some json", :format => :json do
{"beverage" => "coffee"}.to_json
end
Approving a spec
If the contents of the received file is to your liking, you can approve the file by overwriting the approved file with the received file.
For an example who's full description is My Spec
:
mv my_spec.received.txt my_spec.approved.txt
When you rerun the spec, it should now pass.
Expensive computations
The Executable class allows you to perform expensive operations only when the command to execute it changes.
For example, if you have a SQL query that is very slow, you can create an executable with the actual SQL to be performed.
The first time the spec runs, it will fail, allowing you to inspect the results. If this output looks right, approve the query. The next time the spec is run, it will compare only the actual SQL.
If someone changes the query, then the comparison will fail. Both the previously approved command and the received command will be executed so that you can inspect the difference between the results of the two.
verify "an executable" do
sql = subject.expensive_sql # the actual sql as a string
RSpec::Approvals::Executable.new(sql) do |command|
result = ActiveRecord::Base.connection.execute(command)
# do something to display the result
end
end
Copyright (c) 2011 Katrina Owen, released under the MIT license