3 MSpec is a specialized framework that is syntax-compatible with RSpec for
4 basic things like +describe+, +it+ blocks and +before+, +after+ actions. MSpec
5 contains additional features that assist in writing the RubySpecs used by
6 multiple Ruby implementations.
8 MSpec attempts to use the simplest Ruby language features so that beginning
9 Ruby implementations can run the Ruby specs. So, for example, there is not
10 great concern given to constant clashes. Namespacing (or module scoping) is
11 not used because implementing this correctly took a significant amount of work
12 in Rubinius and it is likely that other implementations would also face
15 MSpec is not intended as a replacement for RSpec. MSpec attempts to provide a
16 subset of RSpec's features in some cases and a superset in others. It does not
17 provide all the matchers, for instance. However, MSpec provides several
18 extensions to facilitate writing the Ruby specs in a manner compatible with
19 multiple Ruby implementations.
21 First, MSpec offers a set of guards to control execution of the specs. These
22 guards not only enable or disable execution but also annotate the specs with
23 additional information about why they are run or not run. Second, MSpec
24 provides a different shared spec implementation specifically designed to ease
25 writing specs for the numerous aliased methods in Ruby. The MSpec shared spec
26 implementation should not conflict with RSpec's own shared behavior facility.
27 Third, MSpec provides various helper methods to simplify some specs, for
28 example, creating temporary file names. Finally, MSpec has several specialized
29 runner scripts that includes a configuration facility with a default project
30 file and user-specific overrides.
34 * Use RSpec to run the MSpec specs. There are no plans currently to make
35 the MSpec specs runnable by MSpec.
36 * Don't mock the #hash method as MSpec's Mock implementation uses Hash
37 internally. This can be replaced if necessary, but at this point there is no
38 compelling need to do so.
46 Matchers are additional aids for the verification process. The default
47 is of course to #should or #should_not using the #== operator and its
48 friends but the matchers add a new set of 'operators' to help in the
49 task. They reside in `mspec/matchers/`. There are two broad categories,
50 those that apply to an individual object and those that apply to a
55 - `base` implements the standard #==, #< #<= #>= #> and #=~ with their
56 normal semantics for the objects that you invoke them on.
58 - `be_ancestor_of` is equivalent to checking `obj.ancestors.include?`.
60 - `be_close` is a "delta" for floating-point math. Due to the very
61 nature of it, floating-point comparisons should never be treated as
62 exact. By default the tolerance is 0.00003 but it can be altered if
63 so desired. So `0.23154.should be_close(0.23157)` would succeed
64 (which is usually close enough for floating point unless you are
65 doing some scientific computing.)
67 - `be_empty` checks `obj.empty?`
69 - `be_kind_of` is equivalent to `obj.kind_of?`
71 - `include` is `obj.include?`
75 All of these should be applied to a block created with `lambda` or `proc`:
77 - `complain` is probably clearer stated as `lambda {...}.should complain`;
78 it checks that the block issues a warning. The message can be checked
79 against either a String or a Regexp.
81 - `output` checks that the block produces the given output (stdout as well
82 as stderr, in that order) matched either to a String or a Regexp. This one
83 uses overrides so if that is a problem (for e.g. speccing Readline or
86 - `output_to_fd` is a lower-level version and actually verifies that output
87 to a certain file descriptor is correct whether from an in-/output stream
88 or an actual file. Also can check with either a String or a Regexp.
90 - `raise_error` verifies the exception type (if any) raised by the block it
91 is associated with. The exception class can be given for finer-grained
92 control (inheritance works normally so Exception would catch everything.)
94 == Nested 'describe' blocks
96 MSpec supports nesting one 'describe' block inside another. The examples in
97 the nested block are evaluated with all the before/after blocks of all the
98 containing 'describe' blocks. The following example illustrates this:
100 describe "Some#method" do
105 describe "when passed String" do
110 it "returns false" do
111 # when this example is evaluated, @obj = 1 and @meth = :to_s
116 The output when using the SpecdocFormatter (selected with -fs to the runners)
119 Some#method when passed String
123 == Shared 'describe' blocks
125 MSpec supports RSpec-style shared 'describe' blocks. MSpec also provides a
126 convenience method to assist in writing specs for the numerous aliased methods
127 that Ruby provides. The following example illustrates shared blocks:
129 describe :someclass_some_method, :shared => true do
130 it "does something" do
134 describe "SomeClass#some_method" do
135 it_should_behave_like "someclass_some_method"
138 The first argument to 'describe' for a shared block is an object that
139 duck-types as a String. The representation of the object must be unique. This
140 example uses a symbol. This was the convention for the previous facility that
141 MSpec provided for aliased method (#it_behaves_like). However, this convention
142 is not set in stone (but the uniqueness requirement is). Note that the
143 argument to the #it_should_behave_like is a String because at this time RSpec
144 will not find the shared block by the symbol.
146 MSpec continues to support the #it_behaves_like convenience method for
147 specifying aliased methods. The syntax is as follows:
149 it_behaves_like :symbol_matching_shared_describe, :method [, :object]
151 describe :someclass_some_method, :shared => true do
153 obj.send(@method).should be_true
156 it "returns something else" do
157 @object.send(@method).should be_something_else
162 describe "SomeClass#some_method" do
163 it_behaves_like :someclass_some_method, :other_method
167 describe "SomeOtherClass#some_method" do
168 it_behaves_like :someclass_some_method, :some_method, OtherClass
171 The first form above (#1) is used for typical aliases. That is, methods with
172 different names on the same class that behave identically. The
173 #it_behaves_like helper creates a before(:all) block that sets @method to
174 :other_method. The form of the first example block in the shared block
175 illustrates the typical form of a spec for an aliased method.
177 The second form above (#2) is used for methods on different classes that are
178 essentially aliases, even though Ruby does not provide a syntax for specifying
179 such methods as aliases. Examples are the methods on File, FileTest, and
180 File::Stat. In this case, the #it_behaves_like helper sets both @method and
181 @object in the before(:all) block (@method = :some_method, @object =
182 OtherClass in this example).
184 For shared specs that fall outside of either of these two narrow categories,
185 use nested or shared 'describe' blocks as appropriate and use the
186 #it_should_behave_like method directly.