shoulda-matchers 4.2.0 → 4.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/{MIT-LICENSE → LICENSE} +1 -1
  3. data/README.md +167 -85
  4. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +4 -2
  5. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +3 -2
  6. data/lib/shoulda/matchers/action_controller/permit_matcher.rb +26 -21
  7. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +6 -8
  8. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +6 -8
  9. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +16 -13
  10. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +2 -1
  11. data/lib/shoulda/matchers/action_controller/route_matcher.rb +5 -6
  12. data/lib/shoulda/matchers/action_controller/route_params.rb +1 -1
  13. data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +19 -13
  14. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +18 -16
  15. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +29 -27
  16. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +1 -1
  17. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +5 -5
  18. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +2 -2
  19. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +1 -1
  20. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +1 -1
  21. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +1 -1
  22. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +51 -25
  23. data/lib/shoulda/matchers/active_model/helpers.rb +1 -1
  24. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +32 -30
  25. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +1 -1
  26. data/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +1 -1
  27. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +9 -1
  28. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +2 -2
  29. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +9 -8
  30. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +28 -46
  31. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +33 -9
  32. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +71 -26
  33. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +2 -2
  34. data/lib/shoulda/matchers/active_model/validation_matcher.rb +31 -6
  35. data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +2 -4
  36. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +2 -4
  37. data/lib/shoulda/matchers/active_model/validator.rb +3 -3
  38. data/lib/shoulda/matchers/active_record.rb +26 -23
  39. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +6 -3
  40. data/lib/shoulda/matchers/active_record/association_matcher.rb +118 -47
  41. data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +5 -2
  42. data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +4 -4
  43. data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +1 -1
  44. data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +11 -6
  45. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +14 -15
  46. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +30 -8
  47. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +23 -5
  48. data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +3 -3
  49. data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +1 -1
  50. data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +3 -3
  51. data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +3 -2
  52. data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +7 -5
  53. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +8 -8
  54. data/lib/shoulda/matchers/active_record/have_attached_matcher.rb +185 -0
  55. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +39 -17
  56. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +1 -1
  57. data/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +106 -0
  58. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +12 -10
  59. data/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb +83 -0
  60. data/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +30 -9
  61. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +13 -9
  62. data/lib/shoulda/matchers/active_record/uniqueness.rb +1 -1
  63. data/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +1 -3
  64. data/lib/shoulda/matchers/active_record/uniqueness/test_models.rb +0 -2
  65. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +80 -73
  66. data/lib/shoulda/matchers/doublespeak.rb +2 -1
  67. data/lib/shoulda/matchers/doublespeak/double.rb +1 -1
  68. data/lib/shoulda/matchers/doublespeak/double_collection.rb +3 -3
  69. data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +8 -5
  70. data/lib/shoulda/matchers/doublespeak/object_double.rb +1 -1
  71. data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +1 -5
  72. data/lib/shoulda/matchers/doublespeak/world.rb +2 -2
  73. data/lib/shoulda/matchers/error.rb +1 -1
  74. data/lib/shoulda/matchers/independent.rb +0 -1
  75. data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +14 -13
  76. data/lib/shoulda/matchers/integrations/configuration.rb +1 -1
  77. data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +1 -1
  78. data/lib/shoulda/matchers/integrations/libraries/rails.rb +2 -2
  79. data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +1 -1
  80. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +1 -1
  81. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +1 -1
  82. data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +1 -1
  83. data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +1 -1
  84. data/lib/shoulda/matchers/rails_shim.rb +9 -3
  85. data/lib/shoulda/matchers/util.rb +16 -4
  86. data/lib/shoulda/matchers/util/word_wrap.rb +8 -8
  87. data/lib/shoulda/matchers/version.rb +1 -1
  88. data/lib/shoulda/matchers/warn.rb +3 -3
  89. data/shoulda-matchers.gemspec +10 -7
  90. metadata +11 -9
  91. data/lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb +0 -37
@@ -84,6 +84,8 @@ module Shoulda
84
84
 
85
85
  # @private
86
86
  class HaveDbColumnMatcher
87
+ OPTIONS = %i(precision limit default null scale primary).freeze
88
+
87
89
  def initialize(column)
88
90
  @column = column
89
91
  @options = {}
@@ -95,7 +97,8 @@ module Shoulda
95
97
  end
96
98
 
97
99
  def with_options(opts = {})
98
- %w(precision limit default null scale primary).each do |attribute|
100
+ validate_options(opts)
101
+ OPTIONS.each do |attribute|
99
102
  if opts.key?(attribute.to_sym)
100
103
  @options[attribute.to_sym] = opts[attribute.to_sym]
101
104
  end
@@ -125,23 +128,38 @@ module Shoulda
125
128
 
126
129
  def description
127
130
  desc = "have db column named #{@column}"
128
- desc << " of type #{@options[:column_type]}" if @options.key?(:column_type)
129
- desc << " of precision #{@options[:precision]}" if @options.key?(:precision)
130
- desc << " of limit #{@options[:limit]}" if @options.key?(:limit)
131
- desc << " of default #{@options[:default]}" if @options.key?(:default)
132
- desc << " of null #{@options[:null]}" if @options.key?(:null)
133
- desc << " of primary #{@options[:primary]}" if @options.key?(:primary)
134
- desc << " of scale #{@options[:scale]}" if @options.key?(:scale)
131
+ if @options.key?(:column_type)
132
+ desc << " of type #{@options[:column_type]}"
133
+ end
134
+ if @options.key?(:precision)
135
+ desc << " of precision #{@options[:precision]}"
136
+ end
137
+ desc << " of limit #{@options[:limit]}" if @options.key?(:limit)
138
+ desc << " of default #{@options[:default]}" if @options.key?(:default)
139
+ desc << " of null #{@options[:null]}" if @options.key?(:null)
140
+ desc << " of primary #{@options[:primary]}" if @options.key?(:primary)
141
+ desc << " of scale #{@options[:scale]}" if @options.key?(:scale)
135
142
  desc
136
143
  end
137
144
 
138
145
  protected
139
146
 
147
+ def validate_options(opts)
148
+ invalid_options = opts.keys.map(&:to_sym) - OPTIONS
149
+ if invalid_options.any?
150
+ raise(
151
+ ArgumentError,
152
+ "Unknown option(s): #{invalid_options.map(&:inspect).join(', ')}",
153
+ )
154
+ end
155
+ end
156
+
140
157
  def column_exists?
141
158
  if model_class.column_names.include?(@column.to_s)
142
159
  true
143
160
  else
144
- @missing = "#{model_class} does not have a db column named #{@column}."
161
+ @missing =
162
+ "#{model_class} does not have a db column named #{@column}."
145
163
  false
146
164
  end
147
165
  end
@@ -152,8 +170,9 @@ module Shoulda
152
170
  if matched_column.type.to_s == @options[:column_type].to_s
153
171
  true
154
172
  else
155
- @missing = "#{model_class} has a db column named #{@column} " <<
156
- "of type #{matched_column.type}, not #{@options[:column_type]}."
173
+ @missing =
174
+ "#{model_class} has a db column named #{@column} " <<
175
+ "of type #{matched_column.type}, not #{@options[:column_type]}."
157
176
  false
158
177
  end
159
178
  end
@@ -229,18 +248,21 @@ module Shoulda
229
248
  true
230
249
  else
231
250
  @missing = "#{model_class} has a db column named #{@column} "
232
- if @options[:primary]
233
- @missing << 'that is not primary, but should be'
234
- else
235
- @missing << 'that is primary, but should not be'
236
- end
251
+ @missing <<
252
+ if @options[:primary]
253
+ 'that is not primary, but should be'
254
+ else
255
+ 'that is primary, but should not be'
256
+ end
237
257
  false
238
258
  end
239
259
  end
240
260
 
241
261
  def matched_column
242
262
  @_matched_column ||= begin
243
- column = model_class.columns.detect { |each| each.name == @column.to_s }
263
+ column = model_class.columns.detect do |each|
264
+ each.name == @column.to_s
265
+ end
244
266
  DecoratedColumn.new(model_class, column)
245
267
  end
246
268
  end
@@ -156,7 +156,7 @@ module Shoulda
156
156
 
157
157
  description <<
158
158
  if qualifiers.include?(:unique)
159
- Shoulda::Matchers::Util.a_or_an(index_type) + ' '
159
+ "#{Shoulda::Matchers::Util.a_or_an(index_type)} "
160
160
  else
161
161
  'an '
162
162
  end
@@ -0,0 +1,106 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActiveRecord
4
+ # The `have_implicit_order_column` matcher tests that the model has `implicit_order_column`
5
+ # assigned to one of the table columns. (Rails 6+ only)
6
+ #
7
+ # class Product < ApplicationRecord
8
+ # self.implicit_order_column = :created_at
9
+ # end
10
+ #
11
+ # # RSpec
12
+ # RSpec.describe Product, type: :model do
13
+ # it { should have_implicit_order_column(:created_at) }
14
+ # end
15
+ #
16
+ # # Minitest (Shoulda)
17
+ # class ProductTest < ActiveSupport::TestCase
18
+ # should have_implicit_order_column(:created_at)
19
+ # end
20
+ #
21
+ # @return [HaveImplicitOrderColumnMatcher]
22
+ #
23
+ if RailsShim.active_record_gte_6?
24
+ def have_implicit_order_column(column_name)
25
+ HaveImplicitOrderColumnMatcher.new(column_name)
26
+ end
27
+ end
28
+
29
+ # @private
30
+ class HaveImplicitOrderColumnMatcher
31
+ attr_reader :failure_message
32
+
33
+ def initialize(column_name)
34
+ @column_name = column_name
35
+ end
36
+
37
+ def matches?(subject)
38
+ @subject = subject
39
+ check_column_exists!
40
+ check_implicit_order_column_matches!
41
+ true
42
+ rescue SecondaryCheckFailedError => e
43
+ @failure_message = Shoulda::Matchers.word_wrap(
44
+ "Expected #{model.name} to #{expectation}, " +
45
+ "but that could not be proved: #{e.message}.",
46
+ )
47
+ false
48
+ rescue PrimaryCheckFailedError => e
49
+ @failure_message = Shoulda::Matchers.word_wrap(
50
+ "Expected #{model.name} to #{expectation}, but #{e.message}.",
51
+ )
52
+ false
53
+ end
54
+
55
+ def failure_message_when_negated
56
+ Shoulda::Matchers.word_wrap(
57
+ "Expected #{model.name} not to #{expectation}, but it did.",
58
+ )
59
+ end
60
+
61
+ def description
62
+ expectation
63
+ end
64
+
65
+ private
66
+
67
+ attr_reader :column_name, :subject
68
+
69
+ def check_column_exists!
70
+ matcher = HaveDbColumnMatcher.new(column_name)
71
+
72
+ if !matcher.matches?(@subject)
73
+ raise SecondaryCheckFailedError.new(
74
+ "The :#{model.table_name} table does not have a " +
75
+ ":#{column_name} column",
76
+ )
77
+ end
78
+ end
79
+
80
+ def check_implicit_order_column_matches!
81
+ if model.implicit_order_column.to_s != column_name.to_s
82
+ message =
83
+ if model.implicit_order_column.nil?
84
+ 'implicit_order_column is not set'
85
+ else
86
+ "it is :#{model.implicit_order_column}"
87
+ end
88
+
89
+ raise PrimaryCheckFailedError.new(message)
90
+ end
91
+ end
92
+
93
+ def model
94
+ subject.class
95
+ end
96
+
97
+ def expectation
98
+ "have an implicit_order_column of :#{column_name}"
99
+ end
100
+
101
+ class SecondaryCheckFailedError < StandardError; end
102
+ class PrimaryCheckFailedError < StandardError; end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -35,17 +35,19 @@ module Shoulda
35
35
  def matches?(subject)
36
36
  @subject = subject
37
37
  if readonly_attributes.include?(@attribute)
38
- @failure_message_when_negated = "Did not expect #{@attribute} to be read-only"
38
+ @failure_message_when_negated = "Did not expect #{@attribute}"\
39
+ ' to be read-only'
39
40
  true
40
41
  else
41
- if readonly_attributes.empty?
42
- @failure_message = "#{class_name} attribute #{@attribute} " <<
43
- 'is not read-only'
44
- else
45
- @failure_message = "#{class_name} is making " <<
46
- "#{readonly_attributes.to_a.to_sentence} " <<
47
- "read-only, but not #{@attribute}."
48
- end
42
+ @failure_message =
43
+ if readonly_attributes.empty?
44
+ "#{class_name} attribute #{@attribute} " <<
45
+ 'is not read-only'
46
+ else
47
+ "#{class_name} is making " <<
48
+ "#{readonly_attributes.to_a.to_sentence} " <<
49
+ "read-only, but not #{@attribute}."
50
+ end
49
51
  false
50
52
  end
51
53
  end
@@ -57,7 +59,7 @@ module Shoulda
57
59
  private
58
60
 
59
61
  def readonly_attributes
60
- @readonly_attributes ||= (@subject.class.readonly_attributes || [])
62
+ @_readonly_attributes ||= (@subject.class.readonly_attributes || [])
61
63
  end
62
64
 
63
65
  def class_name
@@ -0,0 +1,83 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActiveRecord
4
+ # The `have_rich_text` matcher tests usage of the
5
+ # `has_rich_text` macro.
6
+ #
7
+ # #### Example
8
+ #
9
+ # class Post < ActiveRecord
10
+ # has_rich_text :content
11
+ # end
12
+ #
13
+ # # RSpec
14
+ # RSpec.describe Post, type: :model do
15
+ # it { should have_rich_text(:content) }
16
+ # end
17
+ #
18
+ # # Minitest (Shoulda)
19
+ # class PostTest < ActiveSupport::TestCase
20
+ # should have_rich_text(:content)
21
+ # end
22
+ #
23
+ # @return [HaveRichTextMatcher]
24
+ #
25
+ def have_rich_text(rich_text_attribute)
26
+ HaveRichTextMatcher.new(rich_text_attribute)
27
+ end
28
+
29
+ # @private
30
+ class HaveRichTextMatcher
31
+ def initialize(rich_text_attribute)
32
+ @rich_text_attribute = rich_text_attribute
33
+ end
34
+
35
+ def description
36
+ "have configured :#{rich_text_attribute} as a "\
37
+ 'ActionText::RichText association'
38
+ end
39
+
40
+ def failure_message
41
+ "Expected #{subject.class} to #{error_description}"
42
+ end
43
+
44
+ def failure_message_when_negated
45
+ "Did not expect #{subject.class} to have ActionText::RichText"\
46
+ " :#{rich_text_attribute}"
47
+ end
48
+
49
+ def matches?(subject)
50
+ @subject = subject
51
+ @error = run_checks
52
+ @error.nil?
53
+ end
54
+
55
+ private
56
+
57
+ attr_reader :error, :rich_text_attribute, :subject
58
+
59
+ def run_checks
60
+ if !has_attribute?
61
+ ":#{rich_text_attribute} does not exist"
62
+ elsif !has_expected_action_text?
63
+ :default
64
+ end
65
+ end
66
+
67
+ def has_attribute?
68
+ @subject.respond_to?(rich_text_attribute.to_s)
69
+ end
70
+
71
+ def has_expected_action_text?
72
+ defined?(ActionText::RichText) &&
73
+ @subject.send(rich_text_attribute).
74
+ instance_of?(ActionText::RichText)
75
+ end
76
+
77
+ def error_description
78
+ error == :default ? description : "#{description} but #{error}"
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -4,12 +4,7 @@ module Shoulda
4
4
  # The `have_secure_token` matcher tests usage of the
5
5
  # `has_secure_token` macro.
6
6
  #
7
- # #### Example
8
- #
9
7
  # class User < ActiveRecord
10
- # attr_accessor :token
11
- # attr_accessor :auth_token
12
- #
13
8
  # has_secure_token
14
9
  # has_secure_token :auth_token
15
10
  # end
@@ -26,14 +21,32 @@ module Shoulda
26
21
  # should have_secure_token(:auth_token)
27
22
  # end
28
23
  #
24
+ # #### Qualifiers
25
+ #
26
+ # ##### ignoring_check_for_db_index
27
+ #
28
+ # By default, this matcher tests that an index is defined on your token
29
+ # column. Use `ignoring_check_for_db_index` if this is not the case.
30
+ #
31
+ # class User < ActiveRecord
32
+ # has_secure_token :auth_token
33
+ # end
34
+ #
35
+ # # RSpec
36
+ # RSpec.describe User, type: :model do
37
+ # it { should have_secure_token(:auth_token).ignoring_check_for_db_index }
38
+ # end
39
+ #
40
+ # # Minitest (Shoulda)
41
+ # class UserTest < ActiveSupport::TestCase
42
+ # should have_secure_token(:auth_token).ignoring_check_for_db_index
43
+ # end
44
+ #
29
45
  # @return [HaveSecureToken]
30
46
  #
31
-
32
- # rubocop:disable Style/PredicateName
33
47
  def have_secure_token(token_attribute = :token)
34
48
  HaveSecureTokenMatcher.new(token_attribute)
35
49
  end
36
- # rubocop:enable Style/PredicateName
37
50
 
38
51
  # @private
39
52
  class HaveSecureTokenMatcher
@@ -41,6 +54,7 @@ module Shoulda
41
54
 
42
55
  def initialize(token_attribute)
43
56
  @token_attribute = token_attribute
57
+ @options = { ignore_check_for_db_index: false }
44
58
  end
45
59
 
46
60
  def description
@@ -49,12 +63,14 @@ module Shoulda
49
63
 
50
64
  def failure_message
51
65
  return if !@errors
66
+
52
67
  "Expected #{@subject.class} to #{description} but the following " \
53
68
  "errors were found: #{@errors.join(', ')}"
54
69
  end
55
70
 
56
71
  def failure_message_when_negated
57
72
  return if !@errors
73
+
58
74
  "Did not expect #{@subject.class} to have secure token " \
59
75
  ":#{token_attribute}"
60
76
  end
@@ -65,6 +81,11 @@ module Shoulda
65
81
  @errors.empty?
66
82
  end
67
83
 
84
+ def ignoring_check_for_db_index
85
+ @options[:ignore_check_for_db_index] = true
86
+ self
87
+ end
88
+
68
89
  private
69
90
 
70
91
  def run_checks
@@ -75,7 +96,7 @@ module Shoulda
75
96
  if !has_expected_db_column?
76
97
  @errors << "missing correct column #{token_attribute}:string"
77
98
  end
78
- if !has_expected_db_index?
99
+ if !@options[:ignore_check_for_db_index] && !has_expected_db_index?
79
100
  @errors << "missing unique index for #{table_and_column}"
80
101
  end
81
102
  @errors
@@ -121,7 +121,9 @@ module Shoulda
121
121
 
122
122
  def description
123
123
  description = "serialize :#{@name}"
124
- description += " class_name => #{@options[:type]}" if @options.key?(:type)
124
+ if @options.key?(:type)
125
+ description += " class_name => #{@options[:type]}"
126
+ end
125
127
  description
126
128
  end
127
129
 
@@ -141,13 +143,12 @@ module Shoulda
141
143
  klass = serialization_coder
142
144
  if klass == @options[:type]
143
145
  true
146
+ elsif klass.respond_to?(:object_class) &&
147
+ klass.object_class == @options[:type]
148
+ true
144
149
  else
145
- if klass.respond_to?(:object_class) && klass.object_class == @options[:type]
146
- true
147
- else
148
- @missing = ":#{@name} should be a type of #{@options[:type]}"
149
- false
150
- end
150
+ @missing = ":#{@name} should be a type of #{@options[:type]}"
151
+ false
151
152
  end
152
153
  else
153
154
  true
@@ -176,9 +177,12 @@ module Shoulda
176
177
  end
177
178
 
178
179
  def expectation
179
- expectation = "#{model_class.name} to serialize the attribute called :#{@name}"
180
+ expectation = "#{model_class.name} to serialize the attribute called"\
181
+ " :#{@name}"
180
182
  expectation += " with a type of #{@options[:type]}" if @options[:type]
181
- expectation += " with an instance of #{@options[:instance_type]}" if @options[:instance_type]
183
+ if @options[:instance_type]
184
+ expectation += " with an instance of #{@options[:instance_type]}"
185
+ end
182
186
  expectation
183
187
  end
184
188