public
Fork of thoughtbot/shoulda
Description: Makes tests easy on the fingers and the eyes
Homepage: http://www.thoughtbot.com/projects/shoulda
Clone URL: git://github.com/rmm5t/shoulda.git
Added new should_change and should_not_change macros; akin to Active Support's 
assert_difference.
Ryan McGeary (author)
Wed Jul 09 06:53:50 -0700 2008
commit  5f786cbff6cdac99a5c60c36534df84854134c6d
tree    2973919c01bea5be90a959c0798160124766d0e9
parent  e6e2f6b906edc4ecd6d7f8a77046216e308d1cf0
...
15
16
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
19
20
...
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
0
@@ -15,6 +15,77 @@ module ThoughtBot # :nodoc:
0
           end
0
           fixtures *all_fixtures
0
         end
0
+        
0
+        # Macro that creates a test asserting a change between the return value
0
+        # of an expression that is run before and after the current setup block
0
+        # is run. This is similar to Active Support's <tt>assert_difference</tt>
0
+        # assertion, but supports more than just numeric values.  See also
0
+        # should_not_change.
0
+        #
0
+        # Example:
0
+        #
0
+        #   context "Creating a post"
0
+        #     setup do
0
+        #       Post.create
0
+        #     end
0
+        #
0
+        #     should_change "Post.count", :by => 1
0
+        #   end
0
+        #
0
+        # As shown in this example, the <tt>:by</tt> option expects a numeric
0
+        # difference between the before and after values of the expression.  You
0
+        # may also specify <tt>:from</tt> and <tt>:to</tt> options:
0
+        #
0
+        #   should_change "Post.count", :from => 0, :to => 1
0
+        #   should_change "@post.title", :from => "old", :to => "new"
0
+        #
0
+        # Combinations of <tt>:by</tt>, <tt>:from</tt>, and <tt>:to</tt> are allowed:
0
+        #
0
+        #   should_change "@post.title"                # => assert the value changed in some way
0
+        #   should_change "@post.title" :from => "old" # => assert the value changed to anything other than "old"
0
+        #   should_change "@post.title" :to   => "new" # => assert the value changed from anything other than "new"
0
+        def should_change(expression, options = {}) 
0
+          by, from, to = get_options!([options], :by, :from, :to)
0
+          stmt = "change '#{expression}'"
0
+          stmt << " from '#{from}'" if from
0
+          stmt << " to '#{to}'" if to
0
+          stmt << " by #{by}" if by
0
+
0
+          expression_eval = lambda { eval(expression) }
0
+          before = lambda do
0
+            @_before_should_change = expression_eval.bind(self).call
0
+            assert_equal from, @_before_should_change, "'#{expression}' was not originally '#{from}'" if from
0
+          end
0
+          should stmt, :before => before do
0
+            old_value = @_before_should_change
0
+            new_value = expression_eval.bind(self).call
0
+            assert_not_equal old_value, new_value, "'#{expression}' did not change" unless by == 0
0
+            assert_equal to, new_value, "'#{expression}' was not changed to '#{to}'" if to
0
+            assert_equal old_value + by, new_value if by
0
+          end
0
+        end
0
+        
0
+        # Macro that creates a test asserting no change between the return value
0
+        # of an expression that is run before and after the current setup block
0
+        # is run. This is the logical opposite of should_change.
0
+        #
0
+        # Example:
0
+        #
0
+        #   context "Updating a post"
0
+        #     setup do
0
+        #       @post.update_attributes(:title => "new")
0
+        #     end
0
+        #
0
+        #     should_not_change "Post.count"
0
+        #   end
0
+        def should_not_change(expression)
0
+          expression_eval = lambda { eval(expression) }
0
+          before = lambda { @_before_should_not_change = expression_eval.bind(self).call }
0
+          should "not change '#{expression}'", :before => before do
0
+            new_value = expression_eval.bind(self).call
0
+            assert_equal @_before_should_not_change, new_value, "'#{expression}' changed"
0
+          end
0
+        end
0
       end
0
       
0
       # Prints a message to stdout, tagged with the name of the calling method.
...
77
78
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
...
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
0
@@ -77,4 +77,35 @@ class HelpersTest < Test::Unit::TestCase # :nodoc:
0
       end
0
     end
0
   end
0
+  
0
+  context "an array of numbers" do
0
+    setup do
0
+      @a = [1, 2, 3]
0
+    end
0
+
0
+    context "after adding another value" do
0
+      setup do
0
+        @a.push(4)
0
+      end
0
+
0
+      should_change "@a.length", :by => 1
0
+      should_change "@a.length", :from => 3
0
+      should_change "@a.length", :to => 4
0
+      should_change "@a[0]", :by => 0
0
+      should_not_change "@a[0]"
0
+    end
0
+
0
+    context "after replacing it with an array of strings" do
0
+      setup do
0
+        @a = %w(a b c d e f)
0
+      end
0
+
0
+      should_change "@a.length", :by => 3
0
+      should_change "@a.length", :from => 3, :to => 6, :by => 3
0
+      should_change "@a[0]"
0
+      should_change "@a[1]", :from => 2, :to => "b"
0
+      should_change "@a[2]", :from => 3
0
+      should_change "@a[3]", :to => "d"
0
+    end
0
+  end
0
 end

Comments