-
Notifications
You must be signed in to change notification settings - Fork 117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Req.Test
: stub anything
#385
Comments
I actually like |
@wojtekmach stubbing options feels to me pretty complex. You have a lot of moving parts and possibly a complex matrix of behaviors. Instead, have you considered just adding |
Req.Test.passthrough unfortunately won’t work because users would already have set:
and so it is too late to opt-out of using plug. |
I suppose we could make it work but it would be really really hacky. (We’d store in private the adapter people might have set and in run_plug/1 adapter we check if we are passing through and if so, bail, call the saved off adapter. I’d rather avoid it because it is adding a lot of coupling that wasn’t there before.) |
It would be hacky in that the plug would essentially run as a proxy and make the original request. Yah maybe a bit hacky but with the value that you don't change the user-facing API and are free to keep making improvements to all this. Another option would be to just support |
not sure what you mean, can you elaborate? Instead of That being said, if passthrough feature can be considered pretty niche, I'm OK making it not completely composable, i.e. it sets the adapter back to the default adapter, Finch. Another completely different option which I think keeps internals cleaner is moving from name-based to URL-based lookups. That is: # config/test.exs
config :myapp, foo_req_options: [adapter: :test]
# lib/foo.ex
def new do
Req.new(
base_url: "http://example.com"
)
|> Req.merge(Application.fetch_env!(:myapp, :foo_req_options))
end
# test/foo_test.exs
Req.Test.stub("example.com", &Req.Test.json(&1, %{foo: 1}))
# test/integration_test.exs
Req.Test.stub("example.com", :passthrough) In |
Of course something closer to what we have right now would totally work too, I'm totally fine special casing # config/test.exs
config :myapp, foo_req_options: [adapter: {:test, Foo}]
# test/foo_test.exs
Req.Test.stub(Foo, &Req.Test.json(&1, %{foo: 1}))
# test/integration_test.exs
Req.Test.stub(Foo, :passthrough) That being said I think there's something to the baseurl-based approach. |
In https://github.com/wojtekmach/req/pull/349/files#diff-455e75050e3f9495a2db20296942753a0f4b6e1a65b96d48127d119a60e38cc4R361 we added a restriction that we can only stub and and expectations for plugs.
@whatyouhide so on Livebook we just had a PR where it would be really convenient if we didn't have this restriction. To give some context, we're integrating with Fly API. Most of the time we want to be hitting a stub. But in integration tests we want to hit the real thing. Our unit and integration tests are both in
Mix.env() == :test
.My idea was the following: https://github.com/livebook-dev/livebook/pull/2708/files#diff-489b337badb7f480b22ff4c701659f5aef800fb470112d4ddf51f39256c2bbbeR249-R273
and then in unit test we'd do:
and in integration tests:
(Of course these test-only helpers are totally optional, the more verbose
Req.Test.stub(Livebook.FlyAPI, fn conn -> ... end)
andReq.Test.stub(Livebook.FlyAPI, :passthrough)
is fine too.)if we forget to set a stub whenever we call FlyAPI in Mix.env :test, we'd get a crash.
When we discussed making Req.Test.stub/2 stricter, our consensus was let's keep it focused on plugs so people don't abuse this feature to stub random unrelated things willy nilly. People can use Mox and/or NimbleOwnership too. That being said, I think this is a legitimate use case that I'd like to support directly in Req.
I think the easiest thing to do is lift the restriction and add
Req.Test.fetch_stub!(name)
so we could implement the above mentioned code using public API. Dunno if we addReq.Test.fetch_expectations!(name)
and what are the semantics.Another idea is to make stubs still stricter but in a different way. Instead of stubbing plugs we stub Req options, usually
plug: ...
. And so:Maybe this is weird because vast majority of time people would be in fact stubbing plugs.
Anyway, regarding stubbing options, we could even do something like:
That is, there is a new
fetch_test_options
step (which only makes sense as the very first step and we'd put it as such) and a correspondingtest_options: name
option which fetches options from stub/mock with that name. And so there is no longer need forplug: {Req.Test, name}
which always felt tiny bit hacky. I don't know if I really like this approach but thought there's maybe something to it?Btw, since day 1 we have a
Req.default_options()
andReq.default_options(options)
which simply store stuff in app env. I used it in my.iex.exs
and occasionally intest/test_helper.exs
. This is completely global so at the moment doesn't play well with multiple Req clients in a single project but maybe using/changing this feature can be helpful in what we want to achieve.cc @jonatanklosko
The text was updated successfully, but these errors were encountered: