Support injecting mock functionality into modules

Add mock registry for a single module.
This commit is contained in:
Michael Miller 2022-12-18 19:04:50 -07:00
parent a3c55dfa47
commit 8f80b10fc1
No known key found for this signature in database
GPG key ID: 32B47AE8F388A1FF
3 changed files with 64 additions and 1 deletions

View file

@ -205,6 +205,25 @@ Spectator.describe "Mocks Docs" do
runnable = mock(Runnable2, command: "echo foo") runnable = mock(Runnable2, command: "echo foo")
expect(runnable.run_one).to eq("Running echo foo") expect(runnable.run_one).to eq("Running echo foo")
end end
context "Injecting Mocks" do
module MyFileUtils
def self.rm_rf(path)
true
end
end
inject_mock MyFileUtils do
stub def self.rm_rf(path)
"Simulating deletion of #{path}"
false
end
end
specify do
expect(MyFileUtils.rm_rf("/")).to be_false
end
end
end end
context "Injecting Mocks" do context "Injecting Mocks" do

View file

@ -1,5 +1,6 @@
require "./method_call" require "./method_call"
require "./mocked" require "./mocked"
require "./mock_registry"
require "./reference_mock_registry" require "./reference_mock_registry"
require "./stub" require "./stub"
require "./stubbed_name" require "./stubbed_name"
@ -157,7 +158,7 @@ module Spectator
{% elsif base == :struct %} {% elsif base == :struct %}
@@_spectator_mock_registry = ::Spectator::ValueMockRegistry(self).new @@_spectator_mock_registry = ::Spectator::ValueMockRegistry(self).new
{% else %} {% else %}
{% raise "Unsupported base type #{base} for injecting mock" %} @@_spectator_mock_registry = ::Spectator::MockRegistry.new
{% end %} {% end %}
private class_getter _spectator_stubs : ::Array(::Spectator::Stub) = [] of ::Spectator::Stub private class_getter _spectator_stubs : ::Array(::Spectator::Stub) = [] of ::Spectator::Stub

View file

@ -0,0 +1,43 @@
require "./mock_registry_entry"
require "./stub"
module Spectator
# Stores collections of stubs for mocked types.
#
# This type is intended for all mocked modules that have functionality "injected."
# That is, the type itself has mock functionality bolted on.
# Adding instance members should be avoided, for instance, it could mess up serialization.
class MockRegistry
@entry : MockRegistryEntry?
# Retrieves all stubs.
def [](_object = nil)
@entry.not_nil!
end
# Retrieves all stubs.
def []?(_object = nil)
@entry
end
# Retrieves all stubs.
#
# Yields to the block on the first retrieval.
# This allows a mock to populate the registry with initial stubs.
def fetch(object : Reference, & : -> Array(Stub))
entry = @entry
if entry.nil?
entry = MockRegistryEntry.new
entry.stubs = yield
@entry = entry
else
entry
end
end
# Clears all stubs defined for a mocked object.
def delete(object : Reference) : Nil
@entry = nil
end
end
end