sonerdy / double Goto Github PK
View Code? Open in Web Editor NEWSimple injectable test dependencies for Elixir
License: MIT License
Simple injectable test dependencies for Elixir
License: MIT License
I could use some help with this one. If a code of conduct will help welcome in new contributors, let's get it done.
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)
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.
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!
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.
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.
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.
allow(:function_name, with: [1,2,3], raises: "Boom!")
Something like that?
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.
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
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
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.
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)
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.
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.