Code Monkey home page Code Monkey logo

delx's Introduction

Delx

Build Status Coverage Status Hex.pm

Defdelegate on steroids! An Elixir library to make function delegation testable.

Prerequisites

  • Erlang 20 or greater
  • Elixir 1.8 or greater

Installation

If available in Hex, the package can be installed by adding delx to your list of dependencies in mix.exs:

def deps do
  [
    {:delx, "~> 3.0"}
  ]
end

Usage

Check out the full docs at https://hexdocs.pm/delx.

Let's say you have the following module.

defmodule Greeter.StringGreeter do
  def hello(name) do
    "Hello, #{name}!"
  end
end

You can delegate functions calls to another module by using the Delx module and calling the defdelegate/2 macro in the module body. It has the same API as Elixir's own Kernel.defdelegate/2 macro.

defmodule Greeter do
  use Delx, otp_app: :greeter

  defdelegate hello(name), to: Greeter.StringGreeter
end

Greeter.hello("Tobi")
# => "Hello, Tobi!"

Testing

One great benefit of Delx is that you can test delegation without invoking the actual implementation of the delegation target, thus eliminating all side effects.

Built-In Assertions

Delx brings it's own test assertions.

All you need to do is to activate delegation mocking for your test environment by putting the following line in your config/test.exs:

config :greeter, Delx, mock: true

Then in your tests, you can import Delx.TestAssertions and use the assert_delegate/2 and refute_delegate/2 assertions.

defmodule GreeterTest do
  use ExUnit.Case

  import Delx.TestAssertions

  describe "hello/1" do
    test "delegate to Greeter.StringGreeter" do
      assert_delegate {Greeter, :hello, 1}, to: Greeter.StringGreeter
    end
  end
end

Note that once you activate mocking all delegated functions do not return anymore but instead raise the Delx.MockedDelegationError. If you really want to call the original implementation, you have to avoid any calls of delegated functions.

With Mox

If you are using Mox in your application you have another possibility to test delegated functions.

Register a mock for the Delx.Delegator behavior to your test/test_helper.exs (or wherever you define your mocks):

Mox.defmock(Greeter.DelegatorMock, for: Delx.Delegator)

Then, in your config/test.exs you have to set the mock as delegator module for your app.

config :my_app, Delx, delegator: Greeter.DelegatorMock

Please make sure not to use the :mock option and a :delegator option at the same time as this may lead to unexpected behavior.

Now you are able to expect calls to delegated functions:

defmodule GreeterTest do
  use ExUnit.Case

  import Mox

  setup :verify_on_exit!

  describe "hello/1" do
    test "delegate to Greeter.StringGreeter" do
      expect(
        Greeter.DelegatorMock,
        :apply,
        fn {Greeter, :hello},
           {Greeter.StringGreeter, :hello},
           ["Tobi"] ->
          :ok
        end
      )

      Greeter.hello("Tobi")
    end
  end
end

For more information on how to implement your own delegator, refer to the docs of the Delx.Delegator behavior.

Note that the configuration is only applied at compile time, so you are unable to mock or replace the delegator module at runtime.

Migration from v2 to v3

Note that the function defdel/2 has been removed in favor of defdelegate/2 to give a better experience with the tooling. Additionally, let's say you want to migrate away from Delx you can simply unuse Delx to fall back to the default Kernel.defdelegate/2 and your code will still work.

The config option to enable testing mode has changed from stub to mock. If you got the following line in your config:

config :greeter, Delx, stub: true

Please change it to:

config :greeter, Delx, mock: true

delx's People

Contributors

tlux avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

nobbz

delx's Issues

Allow runtime delegator configuration

We should allow to change the delegator at runtime as for some test scenarios this may make sense.

Application.put_env(:my_app, Delx, delegator: MyCustomDelegator)

API Suggestion:

defmodule MyModule do
  use Delx, otp_app: :my_app, runtime: true
end

Compile time delegation (runtime: false) should be the default though as runtime delegation is significantly slower.

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.