Forum: RSpec Controller spec: testing that scope is set

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Michael S. (Guest)
on 2009-04-19 20:34
(Received via mailing list)
In a Rails controller I set the scope on a model class in an around
filter. I have defined expectations on the model classes, and ideally, I
would add a further expectation for the scope. Is this already possible
in some way? How would I go about adding support a scope expectation?

Michael

--
Michael S.
mailto:removed_email_address@domain.invalid
http://www.schuerig.de/michael/
Zach D. (Guest)
on 2009-04-19 21:00
(Received via mailing list)
On Sun, Apr 19, 2009 at 12:27 PM, Michael S. 
<removed_email_address@domain.invalid>
wrote:
>
> In a Rails controller I set the scope on a model class in an around
> filter. I have defined expectations on the model classes, and ideally, I
> would add a further expectation for the scope. Is this already possible
> in some way? How would I go about adding support a scope expectation?

How are you setting the said scope?

> removed_email_address@domain.invalid
> http://rubyforge.org/mailman/listinfo/rspec-users
>



--
Zach D.
http://www.continuousthinking.com
http://www.mutuallyhuman.com
Michael S. (Guest)
on 2009-04-19 22:17
(Received via mailing list)
On Sunday 19 April 2009, Zach D. wrote:
> On Sun, Apr 19, 2009 at 12:27 PM, Michael S.
<removed_email_address@domain.invalid> wrote:
> > In a Rails controller I set the scope on a model class in an around
> > filter. I have defined expectations on the model classes, and
> > ideally, I would add a further expectation for the scope. Is this
> > already possible in some way? How would I go about adding support a
> > scope expectation?
>
> How are you setting the said scope?

In an around filter. However, I don't want to test the around filter
mechanism, it might as well be rack middleware instead.

Michael

--
Michael S.
mailto:removed_email_address@domain.invalid
http://www.schuerig.de/michael/
Zach D. (Guest)
on 2009-04-19 22:33
(Received via mailing list)
On Sun, Apr 19, 2009 at 2:09 PM, Michael S. 
<removed_email_address@domain.invalid>
wrote:
>
> In an around filter. However, I don't want to test the around filter
> mechanism, it might as well be rack middleware instead.

Sorry, I don't know what scope means to you in your app. Can you share
your around_filter?
> removed_email_address@domain.invalid
> http://rubyforge.org/mailman/listinfo/rspec-users
>



--
Zach D.
http://www.continuousthinking.com
http://www.mutuallyhuman.com
Michael S. (Guest)
on 2009-04-20 02:45
(Received via mailing list)
On Sunday 19 April 2009, Zach D. wrote:
> On Sun, Apr 19, 2009 at 2:09 PM, Michael S.
<removed_email_address@domain.invalid> wrote:
> >> How are you setting the said scope?
> >
> > In an around filter. However, I don't want to test the around
> > filter mechanism, it might as well be rack middleware instead.
>
> Sorry, I don't know what scope means to you in your app. Can you
> share your around_filter?

Oops, sorry, I assumed the concept from ActiveRecord would be familiar.
If you know ActiveRecord::Base#with_scope that's really all there is. A
scope, within a block or through a proxy, defines options that are
merged with the arguments to #find et al. This merging happens behind
the scenes, therefore the scoped options are effective, but don't show
up as arguments anywhere.

I'm using this in conjunction with a generic query representation
(inspired by JSON Query) that is map through a combination of Rack
middleware and generated around_filters, see below for a glimpse.

Michael


class PeopleController < ApplicationController
  include QueryScope

  query_scope :only => :index do
    # Only allow to filter and order by the
    # virtual name attribute.
    # This attribute is mapped onto the real
    # firstname and lastname attributes.
    allow     :name
    condition :name =>
      "LOWER(firstname || ' ' || lastname) :op LOWER(?)"
    order     :name => "lastname :dir, firstname :dir"
  end
  ...

Somewhere in QueryScope

def query_scope(options = {}, &config_block)
  model_class = extract_resource!(options)
  builder = QueryScopeBuilder.new(config_block)
  around_filter(options) do |controller, action|
    req = builder.build_request_conditioner(controller.request)
    controller.instance_variable_set(:@offset_limit, req.offset_limit)
    model_class.send(:with_scope, :find => req.find_options, &action)
  end
end

--
Michael S.
mailto:removed_email_address@domain.invalid
http://www.schuerig.de/michael/
David C. (Guest)
on 2009-04-20 03:13
(Received via mailing list)
On Sun, Apr 19, 2009 at 5:41 PM, Michael S. 
<removed_email_address@domain.invalid>
wrote:
>> >> > this already possible in some way? How would I go about adding
> Oops, sorry, I assumed the concept from ActiveRecord would be familiar.
It *is* familiar, but setting a model scope from the controller
violates the widely-accepted guideline of skinny controllers and fat
models. I'm guessing that's why Zach wasn't sure what you were talking
about.

> Michael
>    allow     :name
>  builder = QueryScopeBuilder.new(config_block)
>  around_filter(options) do |controller, action|
>    req = builder.build_request_conditioner(controller.request)
>    controller.instance_variable_set(:@offset_limit, req.offset_limit)
>    model_class.send(:with_scope, :find => req.find_options, &action)
>  end
> end

Unless I'm mistaken, it is code like this outside models that was the
underlying motivation for adding named scopes to active record. The
reason it is problematic is that it tends to result in a lot of
duplication outside the models, and makes the controllers really hard
to understand.

Consider this alternative:

describe PeopleController do
  describe "GET index" do
    it "assigns a list of all people filtered by virtual name
attributes" do
      people = [mock_model(Person)]
      Person.stub!(:all).and_return(people)
      people.should_receive(:with_virtual_names).and_return(people)
      get :index
    end
  end
end

class PeopleController
  def index
    @people = PeopleController.all.with_virtual_names
  end
end

Now you can specify what with_virtual_names means in a model spec.
This is easier and far less invasive than trying to specify that
specific filters are applied from the controller spec.

HTH,
David
Michael S. (Guest)
on 2009-04-20 04:31
(Received via mailing list)
On Monday 20 April 2009, David C. wrote:
> On Sun, Apr 19, 2009 at 5:41 PM, Michael S.
<removed_email_address@domain.invalid> wrote:
> >> >> > classes, and ideally, I would add a further expectation for
> >
> > Oops, sorry, I assumed the concept from ActiveRecord would be
> > familiar.
>
> It *is* familiar, but setting a model scope from the controller
> violates the widely-accepted guideline of skinny controllers and fat
> models. I'm guessing that's why Zach wasn't sure what you were
> talking about.

My controllers are anorexic. The functionality I'm trying to spec is
completely generic, I just mix it into the controller.

[snip]
> > end
>
> Unless I'm mistaken, it is code like this outside models that was the
> underlying motivation for adding named scopes to active record. The
> reason it is problematic is that it tends to result in a lot of
> duplication outside the models, and makes the controllers really hard
> to understand.

You are mistaken as there is no duplication at all. Among other things,
I have Rack middleware that maps request like (appropriately escaped)

  /resource/?[?name='Dav*'][/name]

to a params hash like

  { :query => [{:attribute => 'name', :op => '=', :target => 'Dav*'}],
    :order => [{:attribute => 'name'}] }

This, in turn, is interpreted by a RequestConditioner (bad name) which
in this case would, with the help of some mappings passed to it, return

  rc.conditions == ["(firstname || ' ' || lastname) LIKE ?", 'Dav%']
  rc.order      == 'lastname, firstname'

As the last step, these pieces are used to define a scope around certain
controller actions. I could pass them explicitly to, say, #find, but
then I'd have to manually merge them with other conditions.

As to whether this functionality belongs in the model -- I am against
it. What I've described is an adapter layer that translates from one
representation of a query to another. It is not at all related to the
core logic enclosed in the models.


>   end
> end
>
> class PeopleController
>   def index
>     @people = PeopleController.all.with_virtual_names
>   end
> end

That code is sclerotic. I'm building a RIA-client that only requests
JSON-formatted data from the server. Say, I add a date of birth column
to the people grid. Then the most I want to (and have to) do is ensure
that the requisite attribute is whitelisted for querying and contained
in the response data. (Yes, I have JSON "views" with accompanying
specs.)

Taking your non-generic approach, I'd have to repeatedly write and
explicitly test, very similar code. Consider adding date of birth for
sorting and filtering to your example. Then consider writing another
controller that does roughly the same for movies with titles and release
dates. You'll end up with repetitive code. Of course, you're going to
factor out the repetition -- and that's where I already am.

So, long story short, I still think I could make good use of a way to
define an expectation for a specific scope in effect during a #find.
Apart from my current case, this would make it possible to check on
dynamic scopes introduced in Rails 2.3.

Michael

--
Michael S.
mailto:removed_email_address@domain.invalid
http://www.schuerig.de/michael/
David C. (Guest)
on 2009-04-20 05:03
(Received via mailing list)
On Sun, Apr 19, 2009 at 7:19 PM, Michael S. 
<removed_email_address@domain.invalid>
wrote:
>> >> > <removed_email_address@domain.invalid> wrote:
>> >>
>
>> >    req = builder.build_request_conditioner(controller.request)
>
> This, in turn, is interpreted by a RequestConditioner (bad name) which
> it. What I've described is an adapter layer that translates from one
>>       Person.stub!(:all).and_return(people)
>> end
> sorting and filtering to your example. Then consider writing another
> controller that does roughly the same for movies with titles and release
> dates. You'll end up with repetitive code. Of course, you're going to
> factor out the repetition -- and that's where I already am.
>
> So, long story short, I still think I could make good use of a way to
> define an expectation for a specific scope in effect during a #find.
> Apart from my current case, this would make it possible to check on
> dynamic scopes introduced in Rails 2.3.

So what does the controller's index method actually look like?
Zach D. (Guest)
on 2009-04-20 05:38
(Received via mailing list)
On Sun, Apr 19, 2009 at 6:41 PM, Michael S. 
<removed_email_address@domain.invalid>
wrote:
>> >> > this already possible in some way? How would I go about adding
> Oops, sorry, I assumed the concept from ActiveRecord would be familiar.
> Michael
>    allow     :name
>  builder = QueryScopeBuilder.new(config_block)
>  around_filter(options) do |controller, action|
>    req = builder.build_request_conditioner(controller.request)
>    controller.instance_variable_set(:@offset_limit, req.offset_limit)
>    model_class.send(:with_scope, :find => req.find_options, &action)
>  end
> end

In your original post you asked:

   "How would I go about adding support a scope expectation?"

Given the code you've shown it is not clear exactly what you are
expecting. Do you just want to be able to expect that you call
model_class.send(:with_scope) with the appropriate arguments?

I'm sorry if I seem dense, but you have a very clear idea of what you
want to accomplish, but it's coming out very piece meal across
multiple emails and it's quite difficult to pick up on,

--
Zach D.
http://www.continuousthinking.com
http://www.mutuallyhuman.com
Michael S. (Guest)
on 2009-04-20 05:58
(Received via mailing list)
On Monday 20 April 2009, Zach D. wrote:
> In your original post you asked:
>
>    "How would I go about adding support a scope expectation?"
>
> Given the code you've shown it is not clear exactly what you are
> expecting. Do you just want to be able to expect that you call
> model_class.send(:with_scope) with the appropriate arguments?

I'd rather check that a particular scope is in effect for a call to
#find. Just as I said. ;-)

The reason is that I don't want to encumber my controller specs with how
or where the currently effective scope was set. It might have been
multiple nested calls to with_scope or named scopes. In my current code
this is not the case, but that's an implementation detail.

In the specs for the code that does set the scope, an expectation on the
call to with_scope is the right thing. But that's an entirely different
spec at a lower level ob abstraction.

Michael

--
Michael S.
mailto:removed_email_address@domain.invalid
http://www.schuerig.de/michael/
Michael S. (Guest)
on 2009-04-20 05:59
(Received via mailing list)
On Monday 20 April 2009, David C. wrote:

> >>     end
> > requests JSON-formatted data from the server. Say, I add a date of
> > course, you're going to factor out the repetition -- and that's
> > where I already am.
> >
> > So, long story short, I still think I could make good use of a way
> > to define an expectation for a specific scope in effect during a
> > #find. Apart from my current case, this would make it possible to
> > check on dynamic scopes introduced in Rails 2.3.
>
> So what does the controller's index method actually look like?

class PeopleController < ApplicationController
  ...
  def index
    respond_to do |format|
      format.html { render :layout => false }
      format.json do
        @people = Person.all(
          :offset => @offset_limit[0],
          :limit  => @offset_limit[1])
        @count = Person.count
        render
      end
    end
  end
  ...

# app/views/people/index.json.rb
{
  :identifier => Person.primary_key,
  :totalCount => @count,
  :items => @people.map { |p|
    render :partial => 'people/item', :locals => { :person => p }
  }
}

# app/views/people/_item.json.rb
{
  :id => person.id,
  :name => person.name,
  :dob => person.date_of_birth
}

:offset and :limit are the only warts, but I can't set them in a scope
as that would affect the total #count to, not just #find.

Michael

--
Michael S.
mailto:removed_email_address@domain.invalid
http://www.schuerig.de/michael/
Tom S. (Guest)
on 2009-04-20 12:19
(Received via mailing list)
On 20 Apr 2009, at 02:57, Michael S. wrote:
> I'd rather check that a particular scope is in effect for a call to
> #find. Just as I said. ;-)

As is always the case with spec'ing Rails, I don't know which level of
abstraction is the right one to check, but it seems like what you're
asking for is literally:

Person.should_receive(:all) do
   find_scope = Person.send(:scope, :find)
   find_scope[:conditions].should == { name => ["LOWER(firstname || '
' || lastname) = LOWER(?)", 'Dav%'] }
   find_scope[:order].should == { :name => "lastname ASC, firstname
ASC" }
end

However this is obviously getting your hands a bit dirty with Rails
guts -- I suspect others would suggest that you just set an
expectation on with_scope and be done with it (or just load some
fixtures, let the find hit the database, and make sure you get the
right records back? presumably that's wrong in another way, as is
traditional).

Cheers,
-Tom
Zach D. (Guest)
on 2009-04-20 21:41
(Received via mailing list)
On Sun, Apr 19, 2009 at 6:41 PM, Michael S. 
<removed_email_address@domain.invalid>
wrote:
>> >> > this already possible in some way? How would I go about adding
> Oops, sorry, I assumed the concept from ActiveRecord would be familiar.
> Michael
>    allow     :name
>  builder = QueryScopeBuilder.new(config_block)
>  around_filter(options) do |controller, action|
>    req = builder.build_request_conditioner(controller.request)
>    controller.instance_variable_set(:@offset_limit, req.offset_limit)
>    model_class.send(:with_scope, :find => req.find_options, &action)
>  end
> end

I think I am starting to understand what you're after. You want to
ensure the scope defined in your query_scope configuration block in
the controller is used to set the scope on the controller's model.
Right?

With the assumption that that is correct, I would probably refactor
how your #query_scope method works. Right now you're implicitly going
through a QueryScopeBuilder to get a RequestConditioner, in order to
access the #find_options and #offset_limit behaviour on that
RequestConditioner. I would make your controller deal with one object,
perhaps a RequestToQueryTranslator. Your #query_scope method would
come out looking like:

   def query_scope(options = {}, &config_block)
    model_class = extract_resource!(options)
    query = RequestToQueryTranslator.translate(controller.request,
&config_block)
    around_filter(options) do |controller, action|
      controller.instance_variable_set(:@offset_limit,
query.offset_limit)
      model_class.send(:with_scope, :find => query.find_options,
&action)
    end
   end

This simplifies the #query_scope method and gives you more
implementation freedom how your query is constructed. This still
leaves something difficult to spec though, you are passing your
query_scope config_block through, and I'm guessing it is
instance_eval'd. You can't be sure of what's going on in that
config_block unless you actually instance_eval inside of the
appropriate object. This limits your ability to write a clean
object-level example expecting the right query is constructed because
it requires your controller to work with real dependent objects.

Two approaches that come to mind for dealing with this are to change
how your config_block works. Rather than:

  query_scope :only => :index do
    allow     :name
    condition :name =>
      "LOWER(firstname || ' ' || lastname) :op LOWER(?)"
    order     :name => "lastname :dir, firstname :dir"
  end

You could do:

  query_scope :only => :index do |query|
    query.allow     :name
    query.condition :name =>
      "LOWER(firstname || ' ' || lastname) :op LOWER(?)"
    query.order     :name => "lastname :dir, firstname :dir"
  end

Now in your spec, you can write a spec against the query_scope, by
ensuring the passed in object receives #allow, #condition and #order
with appropriate arguments. Now you don't have instance eval the block
in some dependent object somewhere, you can simply pass the query your
RequestToQueryTranslator.translate method returns to the config_block.
This gives you the advantage of ensuring that the controller sets up
the proper query, and it allows you to spec your
RequestToQueryTranslator in isolation to ensure that given a certain
set of method calls that it builds the right find options.

The code is not as pretty I agree because you have to call methods on
the query object passed to your config block. However, the advantage
is that its much easier to spec out, and you're able to right examples
that are clearer than the alternative (ones that ensure magic happens
with a set dependent objects).

WDYT?



--
Zach D.
http://www.continuousthinking.com
http://www.mutuallyhuman.com
Michael S. (Guest)
on 2009-04-20 23:29
(Received via mailing list)
Attachment: query_scope.rb (0 Bytes)
Attachment: request_conditioner.rb (0 Bytes)
Attachment: request_conditioner_spec.rb (0 Bytes)
On Monday 20 April 2009, Zach D. wrote:
> On Sun, Apr 19, 2009 at 6:41 PM, Michael S.
<removed_email_address@domain.invalid> wrote:
[big snip]

> I think I am starting to understand what you're after. You want to
> ensure the scope defined in your query_scope configuration block in
> the controller is used to set the scope on the controller's model.
> Right?

Exactly.

>     query = RequestToQueryTranslator.translate(controller.request,
> &config_block)
>     around_filter(options) do |controller, action|
>       controller.instance_variable_set(:@offset_limit,
> query.offset_limit) model_class.send(:with_scope, :find =>
> query.find_options, &action) end
>    end

I don't agress. Both classes have distinct, although related purposes.
RequestCondition implements the translation from request parameters to
#find-options. QueryScope(Builder) fits it in with ActionController and
adds syntactic sugar. The former is easy to spec, for the latter, I've
been to lazy to figure out a good way.

> WDYT?

I've attached the involved files. I try to avoid doing that on mailing
lists, but we're going in circles otherwise.

In the meantime I've looked into rspec's message expectation in order to
add an expectation for a particular scope being set on an ActiveRecord
class. What I'd need to implement this is a way to get hold of the
partially mocked class. There may not be one.

Michael
Pat M. (Guest)
on 2009-04-20 23:44
(Received via mailing list)
In a functional test, create some records that will be in the scope
and some that will be out of the scope, hit the page and make sure you
only see the ones that you want.  I would either do this with
cucumber, or write a controller spec and verify that only certain
records show in the the assigns var.  Either way you're going to have
to hit the db because obviously the scope affects the db queries.
This is why you'd typically like to keep that stuff in the model.

Pat
Michael S. (Guest)
on 2009-04-21 00:28
(Received via mailing list)
On Monday 20 April 2009, Pat M. wrote:
> In a functional test, create some records that will be in the scope
> and some that will be out of the scope, hit the page and make sure
> you only see the ones that you want.  I would either do this with
> cucumber, or write a controller spec and verify that only certain
> records show in the the assigns var.  Either way you're going to have
> to hit the db because obviously the scope affects the db queries.

Yes, and that feels a bit like cheating.

> This is why you'd typically like to keep that stuff in the model.

I agree on the typically, but disagree specifically.

I've tried my way into rspec, see below, but got stuck at the point
where I'd have to get hold of the model class.

Michael


require 'spec/mocks/message_expectation'

module Spec #:nodoc:
  module Mocks #:nodoc:

    class ScopeExpectation
      def initialize(args)
        @args = args
      end
      def scope_matches?
        # here a miracle occurs
        ...
      end
    end


    module MessageExpectationScopeExtension
      def self.included(base)
        base.send(:alias_method, :matches_without_scope, :matches)
        base.send(:alias_method, :matches, :matches_with_scope)
      end
      def within_scope(*args)
        @scope_expectation = ScopeExpectation.new(args)
        self
      end
      def matches_with_scope(*args, &block)
        matches_without_scope(*args, &block) &&
          (!@scope_expectation || @scope_expectation.scope_matches?)
      end
    end
  end
end

Spec::Mocks::MessageExpectation.class_eval do
  include Spec::Mocks::MessageExpectationScopeExtension
end

--
Michael S.
mailto:removed_email_address@domain.invalid
http://www.schuerig.de/michael/
Pat M. (Guest)
on 2009-04-21 02:48
(Received via mailing list)
On Mon, Apr 20, 2009 at 1:26 PM, Michael S. 
<removed_email_address@domain.invalid>
wrote:
> On Monday 20 April 2009, Pat M. wrote:
>> In a functional test, create some records that will be in the scope
>> and some that will be out of the scope, hit the page and make sure
>> you only see the ones that you want.  I would either do this with
>> cucumber, or write a controller spec and verify that only certain
>> records show in the the assigns var.  Either way you're going to have
>> to hit the db because obviously the scope affects the db queries.
>
> Yes, and that feels a bit like cheating.

What feels like cheating, and why?

Look at the BDD process again.
1. Write failing acceptance test
2. Drill down, write failing unit tests
3. Make unit tests pass.  Go to 2 until
4. Acceptance test passes, go to the pub

In this case, you would
1. Write failing acceptance test
2. Realize that the code you're writing is not unit testable
3. Unit test other parts of code
4. Acceptance test passes, go to the pub


>> This is why you'd typically like to keep that stuff in the model.
>
> I agree on the typically, but disagree specifically.

Agreed, which is why I gave a solution instead of just saying to put
it in the model.

Pat
Zach D. (Guest)
on 2009-04-21 08:17
(Received via mailing list)
On Mon, Apr 20, 2009 at 3:27 PM, Michael S. 
<removed_email_address@domain.invalid>
wrote:
> Exactly.
>>     model_class = extract_resource!(options)
> #find-options. QueryScope(Builder) fits it in with ActionController and
> adds syntactic sugar. The former is easy to spec, for the latter, I've
> been to lazy to figure out a good way.

I'm just suggesting that RequestCondition and QueryScopeBuilder are
encapsulated behind RequestToQueryTranslator, so your controller
doesn't have to know about both of them. Your controller doesn't
actually care about request conditioners and query scope builders. It
only cares that it can translate a request to a query so it can be
used to set the scope on the model.

>
> removed_email_address@domain.invalid
> http://rubyforge.org/mailman/listinfo/rspec-users
>



--
Zach D.
http://www.continuousthinking.com
http://www.mutuallyhuman.com
Zach D. (Guest)
on 2009-04-21 08:22
(Received via mailing list)
On Mon, Apr 20, 2009 at 1:35 PM, Zach D. <removed_email_address@domain.invalid>
wrote:
>>> >> > and ideally, I would add a further expectation for the scope. Is
>>
>>
>>    # firstname and lastname attributes.
>>  model_class = extract_resource!(options)
> the controller is used to set the scope on the controller's model.
>   def query_scope(options = {}, &config_block)
> implementation freedom how your query is constructed. This still
>
>    query.allow     :name
> This gives you the advantage of ensuring that the controller sets up
> the proper query, and it allows you to spec your
> RequestToQueryTranslator in isolation to ensure that given a certain
> set of method calls that it builds the right find options.
>

In addition to this I would still have an example that expected
with_scope to be set on the appropriate model based on the results of
query.find_options, and that @offset_limit was assigned based on the
results of query.offest_limit.


> --
> Zach D.
> http://www.continuousthinking.com
> http://www.mutuallyhuman.com
>



--
Zach D.
http://www.continuousthinking.com
http://www.mutuallyhuman.com
Michael S. (Guest)
on 2009-04-21 12:14
(Received via mailing list)
On Monday 20 April 2009, Zach D. wrote:
> only cares that it can translate a request to a query so it can be
> used to set the scope on the model.

That's already the case. Both of these classes are only internally used
by module QueryScope, which is the only thing a controller sees:

class PeopleController < ApplicationController
  include QueryScope

  query_scope :only => :index do
    # Only allow to filter and order by the
    # virtual name attribute.
    # This attribute is mapped onto the real
    # firstname and lastname attributes.
    allow     :name
    condition :name =>
      "LOWER(firstname || ' ' || lastname) :op LOWER(?)"
    order     :name => "lastname :dir, firstname :dir"
  end

Michael.

--
Michael S.
mailto:removed_email_address@domain.invalid
http://www.schuerig.de/michael/
Zach D. (Guest)
on 2009-04-21 16:57
(Received via mailing list)
On Tue, Apr 21, 2009 at 4:02 AM, Michael S. 
<removed_email_address@domain.invalid>
wrote:
>> actually care about request conditioners and query scope builders. It
>> only cares that it can translate a request to a query so it can be
>> used to set the scope on the model.
>
> That's already the case. Both of these classes are only internally used
> by module QueryScope, which is the only thing a controller sees:

But you're mixing in QueryScope to the controller, it's just like if
you put #query_scope inside of the controller itself. Mixins are a way
to organize and re-use code, but putting code in modules does not
automatically mean you are decoupling parts of your app.

Your controller spec will have to take into account whatever
dependencies your #query_scope method has unless you completely
mock/stub it out, but that seems to work against your goal,

>    condition :name =>
>
> _______________________________________________
> rspec-users mailing list
> removed_email_address@domain.invalid
> http://rubyforge.org/mailman/listinfo/rspec-users
>



--
Zach D.
http://www.continuousthinking.com
http://www.mutuallyhuman.com
Michael S. (Guest)
on 2009-05-22 00:52
(Received via mailing list)
Attachment: rspec-rails.diff (0 Bytes)
Attachment: rspec.diff (0 Bytes)
On Sunday 19 April 2009, Michael S. wrote:
> In a Rails controller I set the scope on a model class in an around
> filter. I have defined expectations on the model classes, and
> ideally, I would add a further expectation for the scope. Is this
> already possible in some way? How would I go about adding support a
> scope expectation?

I've found a way to duck punch my way into Spec::Mocks::Proxy and
Spec::Mocks::MessageExpectation to check in #matches that a scope
expectation is met. I'm stuck now, because I don't see how to
appropriately report a violated expectation. So far, the invasive
changes to both classes are completely general; the Rails-specifics are
patched in from outside. That's how it should be, of course. Can anyone
suggest how to achieve this for reporting?

I've attached the changes I've made so far.

Michael
This topic is locked and can not be replied to.