API
Mocking.activate
— FunctionMocking.activate() -> Nothing
Activates @mock
call sites to allow for calling patches instead of the original function. Intended to be called within a packages test/runtests.jl
file.
Calling this causes functions which use @mock
to become invalidated and re-compiled the next time they are called.
Mocking.activated
— FunctionMocking.activated() -> Bool
Indicates if Mocking has been activated or not via Mocking.activate
.
Mocking.nullify
— FunctionMocking.nullify() -> Nothing
Force any packages loaded after this point to treat the @mock
macro as a no-op. Doing so will maximize performance by eliminating any runtime checks taking place at the @mock
call sites but will break any tests that require patches to be applied.
Note to ensure that all @mock
macros are inoperative be sure to call this function before loading any packages which depend on Mocking.jl.
Mocking.@mock
— Macro@mock expr
Allows the call site function to be temporarily overloaded via an applied patch.
The @mock
macro works as no-op until Mocking.activate
has been called. Once Mocking has been activated then alternative methods defined via @patch
can be used with apply
to call the patched methods from within the apply
context.
Examples
julia> f() = @mock time();
julia> p = @patch time() = 0.0; # UNIX epoch
julia> apply(p) do
Dates.unix2datetime(f())
end
1970-01-01T00:00:00
Mocking.@patch
— Macro@patch expr
Creates a patch from a function definition. A patch can be used with apply
to temporarily include the patch when performing multiple dispatch on @mock
ed call sites.
Mocking.apply
— Functionapply(body::Function, patches) -> Any
Applies one or more patches
during execution of body
. Specifically ,any @mock
call sites encountered while running body
will include the provided patches
when performing dispatch.
Multiple-dispatch is used to determine which method to call when utilizing multiple patches. However, patch defined methods always take precedence over the original function methods.
Ensure you have called activate
prior to calling apply
as otherwise the provided patches will be ignored.
Examples
Applying a patch allows the alternative patch function to be called:
julia> f() = "original";
julia> p = @patch f() = "patched";
julia> apply(p) do
@mock f()
end
"patched"
Patches take precedence over the original function even when the original method is more specific:
julia> f(::Int) = "original";
julia> p = @patch f(::Any) = "patched";
julia> apply(p) do
@mock f(1)
end
"patched"
However, when the patches do not provide a valid method to call then the original function will be used as a fallback:
julia> f(::Int) = "original";
julia> p = @patch f(::Char) = "patched";
julia> apply(p) do
@mock f(1)
end
"original"
Nesting
Nesting multiple apply
calls is allowed. When multiple patches are provided for the same method then the innermost patch takes precedence:
julia> f() = "original";
julia> p1 = @patch f() = "p1";
julia> p2 = @patch f() = "p2";
julia> apply(p1) do
apply(p2) do
@mock f()
end
end
"p2"
When multiple patches are provided for different methods then multiple-dispatch is used to select the most specific patch:
julia> f(::Int) = "original";
julia> p1 = @patch f(::Integer) = "p1";
julia> p2 = @patch f(::Number) = "p2";
julia> apply(p1) do
apply(p2) do
@mock f(1)
end
end
"p1"