Giter Club home page Giter Club logo

double's People

Contributors

brandonjoyce avatar jonrowe avatar jvantuyl avatar sergeykorochansky avatar take-five avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

double's Issues

Code of Conduct

I could use some help with this one. If a code of conduct will help welcome in new contributors, let's get it done.

Function Doubles

We should probably support the ability to provide a function for stubs to use.

stub = double(SomeService) |> allow(:process, fn(arg1, arg2) -> arg1 + arg2 end)
stub.process(1, 2) # 3
assert_receive({:process, 1, 2})

This would be useful for things like returning a random value:

stub = double(SomeService) |> allow(:process, fn -> :rand.uniform(100) end)

Can we make the double a struct?

Thinking through how to make these maps have a better contract. Structs seem like they could work. Will add more acceptance criteria after spiking on that a little bit.

Intermittent failure getting module info

Firstly thanks for making this library! I was thinking of implementing something similar and very glad I came across it.

I'm seeing intermittent failures like this:

  1) test something (MyApp.SomeTest)
     test/my_app/some_test.exs:12
     ** (ArgumentError) argument error
     stacktrace:
       :erlang.get_module_info(MyApp.SomeModule, :functions)

From playing around in iex it appears that :erlang.get_module_info will fail with the argument error unless MyApp.SomeModule.module_info is called first. Once I've called module_info on the module the :erlang call works.

I've worked round this for now by calling .module_info in the setup. It looks like the information you use is in the exports part of what module_info returns and this works for both Erlang and Elixir modules so maybe that would work instead and solve the problem.

Thanks again for the very handy library!

Multiple call return value behavior.

The current behavior is a little confusing. Instead of returning the setup return values in the reverse order that they were setup, let's make the multiple call behavior explicit.

inject = allow(double, :some_function, with: [1], returns: 1, returns: 2, returns: 3)
double.some_function(1) # 1
double.some_function(1) # 2
double.some_function(1) # 3

If multiple setups are defined for the same function name and arg values, then the last one in wins wiping out the original setup.

Swallowing exceptions

Consider the following example:

SomeMod
|> stub(:some_fun, fn _, _ -> Decimal.new(nil) end)

Here, Decimal.new(nil) should raise
** (FunctionClauseError) no function clause matching in Decimal.new/1
but what we get instead is:
** (FunctionClauseError) no function clause matching in nil.some_fun/2.

I think that's due tu this piece.
Maybe there's a way to inspect the exception and reraise if it's coming from inside stub.

Better Errors for Non-module atoms

If you accidentally pass Double an atom that isn't actually a module, you'll just get a cryptic error message "Argument Error". It would be nice if it reported something more clearly about the problem.

Support exceptions

allow(:function_name, with: [1,2,3], raises: "Boom!")

Something like that?

Support verification of stubs on modules with macros.

Logger, for example, has an info/1 macro, so if you try to do this:

logger_stub = Logger
|> double()
|> allow(:info, fn(_msg) -> :ok end)

That will give you an error when verifying the module has a function that matches the name and arity of the stub.

What we need to do is to check the macros defined in the source module as well as the "normal" functions.

Testing messages received from inside another spawned process

It appears that something like this doesn't work correctly.

test "this will fail because the message is sent to the spawned process" do
  inject = double |> allow(:some_function, with: [], returns: :ok)
  test_me()
  assert_receive :some_function
end

defp test_me(inject) do
  spawn fn ->
    inject.some_function.()
  end
end

Support double verifications

inject = expect(double, :some_function, with: [1,2,3])
verify(inject) # throws error or something because the function wasn't called
inject.some_function(1,2,3)
verify(inject) # all good because it was called with expected arguments

Add CI

We should setup travis CI for Elixir 1.3 all the way through 1.8. Preferably setup warnings as errors if we can so compiling double doesn't output a bunch of warnings for users.

Ability to reset stubbed functions

There are times when using shared setups that you may want to overwrite or remove a stubbed function from a double.

Maybe it could look something like this.

stub = double(IO)
|> allow(:puts, fn(_) -> :ok end)
|> unstub(:puts)

Deal with conflicts when two stubbed modules have the same function name/arity

If two modules are stubbed who have the same module/function name:

io_stub = double(IO) |> allow(:puts, fn(_) -> :ok end)
other_stub = double(Other) |> allow(:puts, fn(_) -> :ok end)

Then a call to either stub's puts/1 function will send the test process a message {:puts, "arg"}. This would make it difficult to determine for certain which stub is being called. For example with assert_receive:

assert_receive({:puts, arg}) # Which stub is being called?

Adding the module name to the message makes sense, but is a breaking change ex: {IO, :puts, args}.

However, we've been considering adding a stub alias for allow anyway since that was mostly inspired by RSpec, but it isn't really the same. We could adopt this new 3-tuple behavior when the stub function is used, and stick with the 2-tuple for allow calls.

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.