Class: FlexMock

Inherits:
Object show all
Extended by:
ArgumentTypes
Includes:
Ordering
Defined in:
lib/flexmock/core.rb,
lib/flexmock/rspec.rb,
lib/flexmock/errors.rb,
lib/flexmock/version.rb,
lib/flexmock/ordering.rb,
lib/flexmock/recorder.rb,
lib/flexmock/undefined.rb,
lib/flexmock/validators.rb,
lib/flexmock/call_record.rb,
lib/flexmock/expectation.rb,
lib/flexmock/mock_builder.rb,
lib/flexmock/partial_mock.rb,
lib/flexmock/argument_types.rb,
lib/flexmock/call_validator.rb,
lib/flexmock/mock_container.rb,
lib/flexmock/spy_describers.rb,
lib/flexmock/explicit_needed.rb,
lib/flexmock/argument_matchers.rb,
lib/flexmock/argument_matching.rb,
lib/flexmock/rspec_spy_matcher.rb,
lib/flexmock/core_class_methods.rb,
lib/flexmock/deprecated_methods.rb,
lib/flexmock/expectation_builder.rb,
lib/flexmock/expectation_director.rb,
lib/flexmock/expectation_recorder.rb,
lib/flexmock/minitest_integration.rb,
lib/flexmock/composite_expectation.rb,
lib/flexmock/test_unit_integration.rb,
lib/flexmock/default_framework_adapter.rb,
lib/flexmock/test_unit_assert_spy_called.rb,
lib/flexmock/test_unit_testcase_extensions.rb,
lib/flexmock/extensions/active_record_model.rb
more...

Overview

Permission is granted for use, copying, modification, distribution, and distribution of modified versions of this work as long as the above copyright notice is included. +++

Defined Under Namespace

Modules: ArgumentMatching, ArgumentTypes, Extensions, GenericTestCase, Minitest, MockContainer, Ordering, RSpecMatchers, SpyDescribers, TestCase, TestUnitAssertions Classes: AnyMatcher, AtLeastCountValidator, AtMostCountValidator, CallRecord, CallValidator, CheckFailedError, CompositeExpectation, CountValidator, DefaultFrameworkAdapter, DuckMatcher, EqualMatcher, ExactCountValidator, Expectation, ExpectationBuilder, ExpectationDirector, ExpectationRecorder, ExplicitNeeded, ExtensionRegistry, HashMatcher, MinitestFrameworkAdapter, MockBuilder, MockError, NullParentMock, PartialMockProxy, ProcMatcher, RSpecFrameworkAdapter, Recorder, SignatureValidator, TestUnitFrameworkAdapter, Undefined, UsageError, UseContainer

Constant Summary collapse

CALL_VALIDATOR =
CallValidator.new
ON_RUBY_20 =
(RUBY_VERSION =~ /^2\.0\./)
SpecModule =
Spec
VERSION =
"3.0.1"
CONTAINER_HELPER =
ExtensionRegistry.new
ANY =
AnyMatcher.new
FORBID_MOCKING =
:__flexmock_forbid_mocking
EXP_BUILDER =
ExpectationBuilder.new

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ArgumentTypes

any, ducktype, eq, hsh, on

Methods included from Ordering

#flexmock_allocate_order, #flexmock_current_order, #flexmock_current_order=, #flexmock_groups, #flexmock_validate_order

Constructor Details

#initialize(name = "unknown", container = nil, parent: nil) ⇒ FlexMock

Create a FlexMock object with the given name. The name is used in error messages. If no container is given, create a new, one-off container for this mock.

[View source]

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/flexmock/core.rb', line 66

def initialize(name="unknown", container=nil, parent: nil)
  @flexmock_name = name
  @flexmock_closed = false
  @flexmock_container_stack = Array.new
  @expectations = Hash.new
  @verified = false
  @calls = []
  @base_class = nil
  if parent
    @ignore_missing = parent.ignore_missing?
    @parent_mock = parent
  else
    @ignore_missing = false
    @parent_mock = NullParentMock.new
  end
  container = UseContainer.new if container.nil?
  container.flexmock_remember(self)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args, **kw, &block) ⇒ Object

Handle missing methods by attempting to look up a handler.

[View source]

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/flexmock/core.rb', line 140

def method_missing(sym, *args, **kw, &block)
  FlexMock.verify_mocking_allowed!

  call_record = CallRecord.new(sym, args, kw, block)
  @calls << call_record
  flexmock_wrap do
    if flexmock_closed?
      FlexMock.undefined
    elsif exp = flexmock_expectations_for(sym)
      exp.call(args, kw, block, call_record)
    elsif @base_class && @base_class.flexmock_defined?(sym)
      FlexMock.undefined
    elsif @ignore_missing
      FlexMock.undefined
    else
      super(sym, *args, **kw, &block)
    end
  end
end

Class Attribute Details

.framework_adapterObject (readonly)

Returns the value of attribute framework_adapter.


17
18
19
# File 'lib/flexmock/core_class_methods.rb', line 17

def framework_adapter
  @framework_adapter
end

.partials_are_basedObject

Returns the value of attribute partials_are_based.


51
52
53
# File 'lib/flexmock/core.rb', line 51

def partials_are_based
  @partials_are_based
end

.partials_verify_signaturesObject

Returns the value of attribute partials_verify_signatures.


52
53
54
# File 'lib/flexmock/core.rb', line 52

def partials_verify_signatures
  @partials_verify_signatures
end

Instance Attribute Details

#flexmock_container_stackObject (readonly)

Returns the value of attribute flexmock_container_stack.


48
49
50
# File 'lib/flexmock/core.rb', line 48

def flexmock_container_stack
  @flexmock_container_stack
end

#flexmock_nameObject (readonly)

Returns the value of attribute flexmock_name.


47
48
49
# File 'lib/flexmock/core.rb', line 47

def flexmock_name
  @flexmock_name
end

Class Method Details

.check(msg, &block) ⇒ Object

Check will assert the block returns true. If it doesn’t, an assertion failure is triggered with the given message.

[View source]

121
122
123
124
125
126
127
# File 'lib/flexmock/core_class_methods.rb', line 121

def check(msg, &block)  # :nodoc:
  if FlexMock.framework_adapter.respond_to?(:check)
    FlexMock.framework_adapter.check(msg, &block)
  else
    FlexMock.framework_adapter.make_assertion(msg, &block)
  end
end

.forbid_mocking(mocking_forbidden_return = nil) ⇒ Object

Forbid mock calls to happen while the block is being evaluated

Parameters:

  • mocking_forbidden_return (Object) (defaults to: nil)

    the return value that should be used if a mocking call has happened. If no mocking calls happened, returns the return value of the block

[View source]

58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/flexmock/core_class_methods.rb', line 58

def forbid_mocking(mocking_forbidden_return = nil)
  current, Thread.current[FORBID_MOCKING] =
      Thread.current[FORBID_MOCKING], true

  catch(FORBID_MOCKING) do
    return yield
  end
  mocking_forbidden_return

ensure
  Thread.current[FORBID_MOCKING] = current
end

.format_args(args, kw) ⇒ Object

Class method to format a list of args (the part between the parenthesis).

[View source]

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
112
113
114
115
116
117
# File 'lib/flexmock/core_class_methods.rb', line 87

def format_args(args, kw)
  args =
    if args
      args = args.map do |a|
        FlexMock.forbid_mocking("<recursive call to mocked method in #inspect>") do
          a.inspect
        end
      end
      args.join(', ')
    else
      "*args"
    end

  kw =
    if kw.kind_of? HashMatcher
      kw.inspect
    elsif kw && !kw.empty?
      kw = kw.transform_values do |v|
        FlexMock.forbid_mocking("<recursive call to mocked method in #inspect>") do
          v.inspect
        end
      end
      kw.map { |k, v| "#{k}: #{v}" }.join(', ')
    elsif kw.nil?
      # Don't append **kwargs to signature if ruby version < 3
      # in order to not break existing code still on ruby2
      "**kwargs" unless RUBY_VERSION < "3"
    end

  [(args unless args.empty?), kw].compact.join(", ")
end

.format_call(sym, args, kw) ⇒ Object

Class method to format a method name and argument list as a nice looking string.

[View source]

81
82
83
# File 'lib/flexmock/core_class_methods.rb', line 81

def format_call(sym, args, kw)  # :nodoc:
  "#{sym}(#{format_args(args, kw)})"
end

.undefinedObject

Undefined is normally available as FlexMock.undefined

[View source]

47
48
49
# File 'lib/flexmock/undefined.rb', line 47

def self.undefined
  @undefined
end

.use(*names) ⇒ Object

Class method to make sure that verify is called at the end of a test. One mock object will be created for each name given to the use method. The mocks will be passed to the block as arguments. If no names are given, then a single anonymous mock object will be created.

At the end of the use block, each mock object will be verified to make sure the proper number of calls have been made.

Usage:

FlexMock.use("name") do |mock|    # Creates a mock named "name"
  mock.should_receive(:meth).
    returns(0).once
end                               # mock is verified here

NOTE: If you include FlexMock::TestCase into your test case file, you can create mocks that will be automatically verified in the test teardown by using the flexmock method.

[View source]

39
40
41
42
43
44
45
46
47
48
49
# File 'lib/flexmock/core_class_methods.rb', line 39

def use(*names)
  names = ["unknown"] if names.empty?
  container = UseContainer.new
  mocks = names.collect { |n| container.flexmock(n) }
  yield(*mocks)
rescue Exception => _
  container.got_exception = true
  raise
ensure
  container.flexmock_teardown
end

.verify_mocking_allowed!Object

Verify that mocking is allowed in the current context. Throws if it is not.

[View source]

73
74
75
76
77
# File 'lib/flexmock/core_class_methods.rb', line 73

def verify_mocking_allowed!
  if Thread.current[FORBID_MOCKING]
    throw FORBID_MOCKING
  end
end

Instance Method Details

#by_defaultObject

[View source]

134
135
136
137
# File 'lib/flexmock/core.rb', line 134

def by_default
  @last_expectation.by_default
  self
end

#flexmock_base_classObject

[View source]

180
181
182
# File 'lib/flexmock/core.rb', line 180

def flexmock_base_class
  @base_class
end

#flexmock_based_on(base_class) ⇒ Object

[View source]

184
185
186
187
188
189
190
191
192
# File 'lib/flexmock/core.rb', line 184

def flexmock_based_on(base_class)
  @base_class = base_class
  if base_class <= Kernel
    if self.class != base_class
      should_receive(:class => base_class)
      should_receive(:kind_of?).and_return { |against| base_class <= against }
    end
  end
end

#flexmock_callsObject

Return the list of calls made on this mock. Used in formatting error messages.

[View source]

203
204
205
# File 'lib/flexmock/core.rb', line 203

def flexmock_calls
  @calls
end

#flexmock_closed?Boolean

Returns:

  • (Boolean)
[View source]

123
124
125
# File 'lib/flexmock/core.rb', line 123

def flexmock_closed?
  @flexmock_closed
end

#flexmock_containerObject

[View source]

89
90
91
# File 'lib/flexmock/core.rb', line 89

def flexmock_container
  flexmock_container_stack.last
end

#flexmock_define_expectation(location, *args, **kw) ⇒ Object

Using location, define the expectations specified by args.

[View source]

254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/flexmock/core.rb', line 254

def flexmock_define_expectation(location, *args, **kw)
  @last_expectation = EXP_BUILDER.parse_should_args(self, args, kw) do |method_name|
    exp = flexmock_expectations_for(method_name) || ExpectationDirector.new(method_name)
    @expectations[method_name] = exp
    result = Expectation.new(self, method_name, location)
    exp << result
    override_existing_method(method_name) if flexmock_respond_to?(method_name, true)

    if @base_class && !@base_class.flexmock_defined?(method_name)
      if !ON_RUBY_20 || !@base_class.ancestors.include?(Class)
        result = ExplicitNeeded.new(result, method_name, @base_class)
      end
    end
    result
  end
end

#flexmock_expectations_for(method_name) ⇒ Object

Return the expectation director for a method name.

[View source]

176
177
178
# File 'lib/flexmock/core.rb', line 176

def flexmock_expectations_for(method_name) # :nodoc:
  @expectations[method_name] || @parent_mock.flexmock_expectations_for(method_name)
end

#flexmock_find_expectation(method_name, *args, **kw, &block) ⇒ Object

Find the mock expectation for method sym and arguments.

[View source]

169
170
171
172
173
# File 'lib/flexmock/core.rb', line 169

def flexmock_find_expectation(method_name, *args, **kw, &block) # :nodoc:
  if exp = flexmock_expectations_for(method_name)
    exp.find_expectation(args, kw, block)
  end
end

#flexmock_invoke_original(method_name, args, kw = {}, orig_block = nil) ⇒ Object

Invocke the original non-mocked functionality for the given symbol.

[View source]

209
210
211
# File 'lib/flexmock/core.rb', line 209

def flexmock_invoke_original(method_name, args, kw = {}, orig_block = nil)
  return FlexMock.undefined
end

#flexmock_received?(method_name, args, kw, options = {}) ⇒ Boolean

True if the mock received the given method and arguments.

Returns:

  • (Boolean)
[View source]

197
198
199
# File 'lib/flexmock/core.rb', line 197

def flexmock_received?(method_name, args, kw, options = {})
  CALL_VALIDATOR.received?(@calls, method_name, args, kw, options)
end

#flexmock_respond_to?Object

Save the original definition of respond_to? for use a bit later.

[View source]

161
# File 'lib/flexmock/core.rb', line 161

alias flexmock_respond_to? respond_to?

#flexmock_teardownObject

Teardown and infrastructure setup for this mock.

[View source]

119
120
121
# File 'lib/flexmock/core.rb', line 119

def flexmock_teardown
  @flexmock_closed = true
end

#flexmock_verifyObject

Verify that each method that had an explicit expected count was actually called that many times.

[View source]

108
109
110
111
112
113
114
115
116
# File 'lib/flexmock/core.rb', line 108

def flexmock_verify
  return if @verified
  @verified = true
  flexmock_wrap do
    @expectations.each do |sym, handler|
      handler.flexmock_verify
    end
  end
end

#ignore_missing?Boolean

Returns:

  • (Boolean)
[View source]

85
86
87
# File 'lib/flexmock/core.rb', line 85

def ignore_missing?
  @ignore_missing
end

#inspectObject

Return the inspection string for a mock.

[View source]

102
103
104
# File 'lib/flexmock/core.rb', line 102

def inspect
  "<FlexMock:#{flexmock_name}>"
end

#method(method_name) ⇒ Object

Override the built-in method to include the mocked methods.

[View source]

214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/flexmock/core.rb', line 214

def method(method_name)
  if (expectations = flexmock_expectations_for(method_name))
    ->(*args, **kw, &block) { expectations.call(args, kw, block) }
  else
    super
  end
rescue NameError => ex
  if ignore_missing?
    proc { FlexMock.undefined }
  else
    raise ex
  end
end

#mock_handle(sym, expected_count = nil, &block) ⇒ Object

Handle all messages denoted by sym by calling the given block and passing any parameters to the block. If we know exactly how many calls are to be made to a particular method, we may check that by passing in the number of expected calls as a second paramter.

[View source]

40
41
42
43
44
# File 'lib/flexmock/deprecated_methods.rb', line 40

def mock_handle(sym, expected_count=nil, &block) # :nodoc:
  $stderr.puts "mock_handle is deprecated, " +
    "use the new should_receive interface instead."
  self.should_receive(sym).times(expected_count).returns(&block)
end

#pop_flexmock_containerObject

[View source]

97
98
99
# File 'lib/flexmock/core.rb', line 97

def pop_flexmock_container
  flexmock_container_stack.pop
end

#push_flexmock_container(container) ⇒ Object

[View source]

93
94
95
# File 'lib/flexmock/core.rb', line 93

def push_flexmock_container(container)
  flexmock_container_stack.push(container)
end

#respond_to?(sym, *args) ⇒ Boolean

Override the built-in respond_to? to include the mocked methods.

Returns:

  • (Boolean)
[View source]

164
165
166
# File 'lib/flexmock/core.rb', line 164

def respond_to?(sym, *args)
  super || (@expectations[sym] ? true : @ignore_missing)
end

#should_expect {|Recorder.new(self)| ... } ⇒ Object

Declare that the mock object should expect methods by providing a recorder for the methods and having the user invoke the expected methods in a block. Further expectations may be applied the result of the recording call.

Example Usage:

mock.should_expect do |record|
  record.add(Integer, 4) { |a, b|
    a + b
  }.at_least.once

Yields:

[View source]

283
284
285
# File 'lib/flexmock/core.rb', line 283

def should_expect
  yield Recorder.new(self)
end

#should_ignore_missingObject Also known as: mock_ignore_missing

Ignore all undefined (missing) method calls.

[View source]

128
129
130
131
# File 'lib/flexmock/core.rb', line 128

def should_ignore_missing
  @ignore_missing = true
  self
end

#should_receive(*args, **kw) ⇒ Object

:call-seq:

mock.should_receive(:method_name)
mock.should_receive(:method1, method2, ...)
mock.should_receive(:meth1 => result1, :meth2 => result2, ...)

Declare that the mock object should receive a message with the given name.

If more than one method name is given, then the mock object should expect to receive all the listed melthods. If a hash of method name/value pairs is given, then the each method will return the associated result. Any expectations applied to the result of should_receive will be applied to all the methods defined in the argument list.

An expectation object for the method name is returned as the result of this method. Further expectation constraints can be added by chaining to the result.

See Expectation for a list of declarators that can be used.

[View source]

247
248
249
# File 'lib/flexmock/core.rb', line 247

def should_receive(*args, **kw)
  flexmock_define_expectation(caller, *args, **kw)
end