Skip to content
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

No defined way to test composition of middleware #48

Open
nickcampbell18 opened this issue Apr 17, 2018 · 3 comments
Open

No defined way to test composition of middleware #48

nickcampbell18 opened this issue Apr 17, 2018 · 3 comments

Comments

@nickcampbell18
Copy link
Contributor

nickcampbell18 commented Apr 17, 2018

Problem

Let's say I have a large application, with many middleware. Some middleware are simply composition units of others, for example:

class Middleware::Authenticate
  uses Middleware::ExtractBearerToken
  uses Middleware::LookupBearerToken
  uses Middleware::LogBearerToken

  requires :bearer_token
  provides :user

  def call
    provide(user: bearer_token.user)
    next_middleware.call
  end
end

I think this is a use-case which isn't currently tested well:

  • We have boot-time checking of the dependency tree (so we check that ExtractBearerToken provides :bearer_token)
  • We have unit tests of each sub-middleware behaving in the correct way in isolation.
  • We have request specs testing the overall route (including interactions of all the other middleware).

But there doesn't seem to be a simple way of saying, in a test, "run this smaller middleware chain" (i.e. invoke each sub-middleware and then run Middleware::Authenticate#call). The behaviours of this unit might vary depending on inputs/outputs of each sub-middleware in a way which isn't best expressed in isolated unit tests nor in the high-level request specs (which can be slow).

I think that endorsing this kind of testing to uncover interaction edge-cases would be incredibly valuable.

Proposal

Add a high-level API, either to coach/rspec or in the README, for running a full middleware chain like this.

The usage would look something like:

describe Middleware::Authenticate do
  subject(:instance) { Coach::Chain.new(described_class) } # this is the interesting bit
  
  it { is_expected.to call_next_middleware }
  it { is_expected.to provide(user: ...) }

  context "when a bearer token isn't in the request" do
    it "bails out before calling the main function"
  end
end
@nickcampbell18 nickcampbell18 changed the title No easy way to test composition of middleware No defined way to test composition of middleware Apr 17, 2018
@nickcampbell18
Copy link
Contributor Author

I'm aware that we could use Coach::Handler to construct a full request handler object, but that seems like overkill in specs.

@tragiclifestories
Copy link

I'm assuming we'll need some way to vary the actual input to the call, would it maybe look like

subject(:instance) { Coach::Chain.new(described_class, request: request) }

Maybe?

@dmagliola
Copy link
Contributor

+1, this bit me HARD

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants