Refactoring of simple Model test for Rails
1 2 # ============================================================================= 3 # Purpose: Refactored TestCase for simple Rails ActiveRecord::Base and 4 # ActiveForm classes. 5 # Author: Manuel Holtgrewe <purestorm at ggnore dot net> 6 # License: Public Domain 7 # 8 # Feel free to flesh out the tests further and make it a more poweful library. 9 # Drop me a line if you find the module useful or if you created something more 10 # powerful on top of it. 11 # ============================================================================= 12 # 13 # Include this module in your test classes. Then, you define some valid data, 14 # the model class to test and some "patches" to the valid data to make it invalid. 15 # 16 # Sure, this will only work for very simple models but you want to spend as few 17 # time on those as possible, right? 18 # 19 # Assuming you have the following model: 20 # 21 # class MyModel < ActiveRecord::Base 22 # validates_length_of :title, :in => 10..100 23 # validates_numericality_of :number 24 # end 25 # 26 # You can then write the following TestCase: 27 # 28 # class MyModelTest < Test::Unit::TestCase 29 # include SimpleMethodTests # The basic tests are defined in this module. 30 # 31 # fixtures :my_models 32 # 33 # def setup 34 # @model_class = MyModel 35 # @valid_data = { :title => 'Abracabra!', :number => 10 } 36 # @invalid_patches = 37 # [ 38 # [ :title, nil ], [ :title, 'a' * 9 ], [ :title, 'a' * 101 ], 39 # [ :number, nil ], [ :number, 'a' ], [ :title, '123a' ], 40 # ] 41 # end 42 # 43 # def test_a_nonbasic_test 44 # flunk, "Wheee!" 45 # end 46 # 47 # # Overwrite a test from the mixin. 48 # def test_valid_should_return_false_and_add_errors_with_invalid_data 49 # assert true, "Removing this test!" 50 # end 51 # end 52 # 53 # You can both test ActiveRecord::Base and ActiveForm classes (CRUD is not tested 54 # on ActiveForm classes). If you test ActiveRecord::Base classes then you have to 55 # provide at least one fixture. 56 module SimpleModelTests 57 def test_valid_should_return_true_with_valid_data 58 # Do not use Model.new(attributes) since some might be marked as protected. 59 model = @model_class.new 60 @valid_data.each { |key, value| model.send("#{key}=".to_sym, value) } 61 62 assert model.valid? 63 assert_equal 0, model.errors.count 64 end 65 66 def test_valid_should_return_false_and_add_errors_with_invalid_data 67 @invalid_patches.each do |key, value| 68 invalid_data = @valid_data.dup 69 invalid_data[key] = value 70 71 # Do not use Model.new(attributes) since some might be marked as protected. 72 model = @model_class.new 73 invalid_data.each { |invalid_key, invalid_value| model.send("#{invalid_key}=".to_sym, invalid_value) } 74 75 assert !model.valid?, "invalid_data[#{key.inspect}] == #{value.inspect}, errors: #{model.errors.full_messages.join('; ')}" 76 77 # If the property we set was a foreign key named NAME_id then the error 78 # gets added to the property NAME of the object if the object is an 79 # ActiveRecord::Base object. 80 if key.to_s =~ /^(.*)_id$/ and model.respond_to?($1.to_sym) then 81 assert_not_nil model.errors.on($1.to_sym), "invalid_data[#{$1.to_sym.inspect}] == #{value.inspect}" 82 else 83 assert_not_nil model.errors.on(key), "invalid_data[#{key.inspect}] == #{value.inspect}" 84 end 85 end 86 end 87 88 def test_create_should_work_correctly 89 # We only want to test this if we test an ActiveRecord::Base class. 90 return if not @model_class.new.respond_to?(:save) 91 92 old_count = @model_class.count 93 94 # Do not use Model.new(attributes) since some might be marked as protected. 95 model = @model_class.new 96 @valid_data.each { |key, value| model.send("#{key}=".to_sym, value) } 97 98 assert model.save, "errors: #{model.errors.full_messages.join('; ')}" 99 assert model.reload 100 101 assert_equal old_count+1, @model_class.count 102 end 103 104 def test_update_should_work_correctly 105 # We only want to test update if the model objects have a method "save". 106 return if not @model_class.new.respond_to?(:update) 107 108 # We assume that there is at least one valid record in the database with 109 # different data than the @valid_data you specified above. 110 # 111 # We order by id to make the result predictable. 112 model = @model_class.find(:first, :order => 'id ASC') 113 114 @valid_data.each { |key, value| model.send("#{key}=".to_sym, value) } 115 116 assert model.save, "errors: #{model.errors.full_messages.join('; ')}" 117 assert model.reload 118 119 @valid_data.each do |key, value| 120 case value 121 when Float then 122 assert_in_delta value, model.send(key), 0.01 123 else 124 assert_equal value, model.send(key) 125 end 126 end 127 end 128 129 def test_destroy_should_work_correctly 130 # We only want to test this if we test an ActiveRecord::Base class. 131 return if not @model_class.new.respond_to?(:destroy) 132 133 old_count = @model_class.count 134 135 model = @model_class.find(:first) 136 137 id = model.id 138 139 model.destroy 140 141 assert_raises(ActiveRecord::RecordNotFound) { @model_class.find(id) } 142 143 assert_equal old_count-1, @model_class.count 144 end 145 end