Pretend.jl is a test doubles library.
The main idea is that you can annotate any functions
as @mockable.  Then, you can easily stub out calls to the function with your
own patch.
The following examples demonstrate the basic usage of the Pretend framework.
Pretend.activate()   # Turn on the Pretend framework
# Annotate any function with @mockable macro
@mockable add(x, y) = x + y
# Apply a patch
apply(add => (x,y) -> x - y) do
    @test add(1, 2) == -1
end
# Apply a patch conditionally
apply(add => (x,y) -> x == y ? 0 : Fallback()) do
    @test add(1, 2) == 3
    @test add(5, 5) == 0
end
# Verification
@mockable foo() = bar(1,2)
@mockable bar(x,y) = x * y
spy() do
    foo()
    @test called_exactly_once(bar, 1, 2)
end
# Mocking thirdparty methods
@mockable Base.sin(x::Real)
fakesin(x::Real) = 10
apply(sin => fakesin) do
    @test sin(1.0) == 10
end
# Mocking anonymous functions
add_curry(n) = (x) -> x + n
add1 = mocked(add_curry(1))  # function, not macro
apply(add1 => (x) -> x + 10) do
    @test add1(1) == 11
endThe @mockable macro rewrites a method definition by wrapping around the logic that is
switched on when Pretend.activated() returns true.  The logic basically looks up
a patch in the "patch store" having the same method signature.  If a patch is found
then it will be called.  However, if a patch is not found or if the patch returns
the Fallback() singleton object, the existing method body will be executed.
The apply function sets up the "patch store" with the user-supplied patch functions before
running the body.  As it exits the current scope, the patch store is unwound to the previous
state; hence, no more patch will be applied.  This ensures a clean slate whenever patches
are applied.
Both apply and spy functions keep track of executions of mockable functions. The
difference is that apply expects a set of patches while spy does not take any patch.
Because the @mockable macro needs to be used at the function definition, it's a little tricky
if you want to mock a third party function that you do not own.  To overcome this issue, you may
define a function in your own package and delegate the call to the third party function, and then
you can annotate this function as mockable.
For convenience, when you put @mockable just in front of a third-party method signature then
it will be expanded to a delegate function having the same function name.
Functions are first-class in Julia, and a function can be created at any time on-the-fly. A common usage is high-order functions or closures. Consider the following function:
add_curry(n) = (x) -> x + nIt's easy to annotate add_curry with @mockable but perhaps I
don't want to mock add_curry itself but the function that it returns:
add1 = add_curry(1)In order to mock add1, I would use the mocked function as follows:
add1 = mocked(add_curry(1))There are several mocking libraries available. If Pretend.jl does not fit your needs, take a look at these alternatives:
Mocking.jl has a different design such that the mocks are annotated at the call site rather than at the function definition.
SimpleMock.jl is a very cool package that implements mocking using Cassette.jl's machinery.