Document mock modules

This commit is contained in:
Michael Miller 2022-06-04 18:21:08 -06:00
parent 4de04b2a91
commit cb93f4eee0
No known key found for this signature in database
GPG key ID: 32B47AE8F388A1FF
2 changed files with 59 additions and 0 deletions

View file

@ -7,7 +7,31 @@ require "./value_mock_registry"
require "./value_stub" require "./value_stub"
module Spectator module Spectator
# Module providing macros for defining new mocks from existing types and injecting mock features into concrete types.
module Mock module Mock
# Defines a type that inherits from another, existing type.
# The newly defined subtype will have mocking functionality.
#
# Methods from the inherited type will be overridden to support stubs.
# *base* is the keyword for the type being defined - class or struct.
# *mocked_type* is the original type to inherit from.
# *type_name* is the name of the new type to define.
# An optional *name* of the mock can be provided.
# Any key-value pairs provided with *value_methods* are used as initial stubs for the mocked type.
#
# A block can be provided to define additional methods and stubs.
# The block is evaluated in the context of the derived type.
#
# ```
# Mock.define_subtype(:class, SomeType, meth1: 42, meth2: "foobar") do
# stub abstract def meth3 : Symbol
#
# # Default implementation with a dynamic value.
# stub def meth4
# Time.utc
# end
# end
# ```
macro define_subtype(base, mocked_type, type_name, name = nil, **value_methods, &block) macro define_subtype(base, mocked_type, type_name, name = nil, **value_methods, &block)
{% begin %} {% begin %}
{% if name %}@[::Spectator::StubbedName({{name}})]{% end %} {% if name %}@[::Spectator::StubbedName({{name}})]{% end %}
@ -46,6 +70,32 @@ module Spectator
{% end %} {% end %}
end end
# Injects mock functionality into an existing type.
#
# Generally this method of mocking should be avoiding.
# It modifies types being tested, the mock functionality won't exist outside of tests.
# This option should only be used when sub-types are not possible (e.g. concrete struct).
#
# Methods in the type will be overridden to support stubs.
# The original method functionality will still be accessible, but pass through mock code first.
# *base* is the keyword for the type being defined - class or struct.
# *type_name* is the name of the type to inject mock functionality into.
# An optional *name* of the mock can be provided.
# Any key-value pairs provided with *value_methods* are used as initial stubs for the mocked type.
#
# A block can be provided to define additional methods and stubs.
# The block is evaluated in the context of the derived type.
#
# ```
# Mock.inject(:struct, SomeType, meth1: 42, meth2: "foobar") do
# stub abstract def meth3 : Symbol
#
# # Default implementation with a dynamic value.
# stub def meth4
# Time.utc
# end
# end
# ```
macro inject(base, type_name, name = nil, **value_methods, &block) macro inject(base, type_name, name = nil, **value_methods, &block)
{% begin %} {% begin %}
{% if name %}@[::Spectator::StubbedName({{name}})]{% end %} {% if name %}@[::Spectator::StubbedName({{name}})]{% end %}

View file

@ -1,7 +1,16 @@
require "./method_call" require "./method_call"
require "./stub"
require "./stubbable" require "./stubbable"
require "./unexpected_message"
module Spectator module Spectator
# Mix-in used for mocked types.
#
# Bridges functionality between mocks and stubs
# Implements the abstracts methods from `Stubbable`.
# Types including this module will need to implement `#_spectator_stubs`.
# It should return a mutable list of stubs.
# This is used to store the stubs for the mocked type.
module Mocked module Mocked
include Stubbable include Stubbable