Giter Site home page Giter Site logo

appunite / mockery Goto Github PK

View Code? Open in Web Editor NEW
91.0 3.0 10.0 236 KB

Simple mocking library for asynchronous testing in Elixir.

Home Page: https://hex.pm/packages/mockery

License: Apache License 2.0

Elixir 100.00%
elixir-lang elixir exunit asynchronous-tests mock-library mocking

mockery's Issues

Would you like this helper module?

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

Allow to use module attributes in assert_called

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"]]

Elixir compile emits warning when providing variable to assert_called list of arguments

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:

  • test compile and run without warnings or errors

Actual result:

  • compiler emits warning:
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]))

Improve failure output when using pinned variables

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:
  ...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.