appunite / mockery Goto Github PK
View Code? Open in Web Editor NEWSimple mocking library for asynchronous testing in Elixir.
Home Page: https://hex.pm/packages/mockery
License: Apache License 2.0
Simple mocking library for asynchronous testing in Elixir.
Home Page: https://hex.pm/packages/mockery
License: Apache License 2.0
I've written a helper module that I can work into a pull request, if you like. Here's the moduledoc and the doc for the main function:
@moduledoc """
A shorthand notation for `Mockery` that makes more pretty the common case
of returning a specific return value for a given set of arguments, as
in:
use Given
given Map.get(%{}, :key), return: "5"
Note that the first argument to `given` looks like an ordinary function call.
It is also common to have a "don't care" argument, like this:
given Map.get(@any, :key), return: "5"
See `given/2` for more.
"""
@doc """
Takes what looks like a function call, plus a return value, and arranges that
such a function call will return the given value whenever it's made at a
["seam"](https://www.informit.com/articles/article.aspx?p=359417&seqNum=2)
marked with `Mockery.mockable/1`.
# Code:
... mockable(Schema).changeset(struct, params) ...
# Test:
given Schema.changeset(%Schema{}, %{age: "3"}), return: %Changeset{...}
The function's arguments and return value can be constants, as shown
above, or they can be calculations or variables. That can be helpful
when the `given` appears in a test helper:
def helper(params, cast_value, something_else) do
...
given Schema.changeset(%Schema{}, params), return: cast_value
...
assert ...
end
A function argument can be the special value `@any` (defined when
the module is `used`). That's useful when the argument is irrelevant
and you don't want to have to type it out:
given Schema.changeset(@any, params), return: cast_value
`@any` expands to a function whose value is always `true`. More generally,
any function used as an argument is not matched with equality. Instead, the
call-time value is passed to the function, which should return a truthy value
to indicate a match. So you can do this:
given Module.f(5, &even/1), return: 8
Notes:
* You can provide return values for many arglist values.
given Module.f(5, &even/1), return: 8
given Module.f(6, @any), return: 9
* If there's more than one match, the first is used.
* If the same arglist is given twice, the second replaces the first.
This is useful for `setup` methods:
def setup do
given RunningExample.params(:a_runnable), return: %{}
...
test "..."
given RunningExample.params(:a_runnable), return: %{"a" => "1"}
assert Steps.runnable(:a_runnable) == %{a: 1}
end
* If a function has a `given` value for one or more arglists, but none
matched, an error is thrown.
"""
defmacro given(funcall, return: value) do
Example code:
defmodule SomeModule do
def execute(a), do: a
end
defmodule SomethingOther do
import Mockery.Macro
def new(params), do: mockable(SomeModule).execute(params)
end
Example test:
defmodule TestAppTest do
use ExUnit.Case
use Mockery
describe "some context" do
setup do
{:ok, params: %{a: 1}}
end
test "it should not give a warning here", %{params: params} do
mock(SomeModule, [execute: 1], %{"some_key" => "some value"})
SomethingOther.new(params)
assert_called(SomeModule, :execute, [params])
end
end
end
Expected result:
Actual result:
warning: variable "params" is unused (if the variable is not meant to be used, prefix it with an underscore)
test/test_app_test.exs:15: TestAppTest."test some context it should not give warning here"/1
(note that line 15 is: assert_called(SomeModule, :execute, [params])
)
As the title suggests, the output is currently not very helpful when using pinned variables.
See an example below:
assert_called Redix, :pipeline, [
:redix,
[
["HSET", ^access_token_namespace, ^id, ^access_token],
["EXPIRE", ^access_token_namespace, ^id, _],
["HSET", ^refresh_token_namespace, ^id, ^refresh_token],
["EXPIRE", ^refresh_token_namespace, ^id, _]
]
]
If then the test fails the output looks like this (output shortened by using <placeholders>
):
Redix.pipeline was not called with given arguments
Given:
[:redix, [["HSET", ^access_token_namespace, ^id, ^access_token], ["EXPIRE", ^access_token_namespace, ^id, _], ["HSET", ^refresh_token_namespace, ^id, ^refresh_token], ["EXPIRE", ^refresh_token_namespace, ^id, _]]]
History:
[:redix, [["HSET", "<namespace>", "<id>", "<access token>"], ["EXPIRE", "<namespace>", "<id>", <expire>], ["HSET", "<namespace>", "<id>", "<refresh token>"], ["EXPIRE", "<namespace>", "<id>", <expire>]]]
code: assert_called Redix, :pipeline, [
stacktrace:
...
This makes it very, very hard to find out why a particular test fails.
Compare this to how ex_unit
handles pinned variables:
match (=) failed
The following variables were pinned:
access_token = "<access token>"
access_token_namespace = "<namespace>"
refresh_token = "<refresh token>"
refresh_token_namespace = "<namespace>"
id = <id>
code: assert [:redix, [["HSET", ^access_token_namespace, ^id, ^access_token], ["EXPIRE", ^access_token_namespace, ^id, _], ["HSET", ^refresh_token_namespace, ^id, ^refresh_token], ["EXPIRE", ^refresh_token_namespace, ^id, _]]] = commands
right: [
["HSET", "<namespace>",
"<id>",
"<access token>"],
["EXPIRE", "<namespace>",
"<id>", <expiry>],
["HSET", "<namespace>",
"<id>",
"<refresh_token>"],
["EXPIRE", "<namespace>",
"<id>", <expiry>]
]
stacktrace:
...
When I try to use module attributes in an assert_called
match, I receive the following error:
== Compilation error in file test/authentication/storage/redis_test.exs ==
** (FunctionClauseError) no function clause matching in Kernel.@/1
(elixir) expanding macro: Kernel.@/1
Example for match:
assert_called Redix, :command, [:redix, ["HSET", @namespace, "key", "value"]]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.