Why:
* The `route` matcher can not only be used within controller example
groups but also routing example groups.
* Now that we are mixing matchers into specific example groups, `route`
is no longer available in routing example groups.
To satisfy the above:
* Create a new module that contains a `route` method and returns a new
instance of RouteMatcher. (RouteMatcher still lives in the
ActionController namespace.)
* Mix this module into routing example groups when the gem configuration
block is run.
You can now say `define_class('Models::User')` and it will define a User
class inside of the Models module.
Similarly, you can also say `define_model('Models::User')` and it will
set the table name of the model to `models_users` instead of just
`users`.
When specifying a custom subject, a straightforward usage of
`delegate_method`, such as the following
class UserPresenter
delegate :id, to: :user
attr_reader :user
def initialize(user)
@user = user
end
end
class UserPresenterTest < ActiveSupport::TestCase
subject { UserPresenter.new(User.new) }
should delegate_method(:id).to(:user)
end
would error with something like:
ArgumentError: wrong number of arguments (0 for 1)
This happens because the `should` method in shoulda-context asks the
DelegateMethodMatcher object for its description so that it can use it
to give the test a name and create a method that Test::Unit can run.
Now, the matcher's description needs a subject in order to determine
whether a class or an instance is being tested here -- if a class is
being tested the description will be "should delegate #id to \#user
object", if a class then "should delegate .id to .user object".
Unfortunately the matcher doesn't know what the subject is before
its #description method is called -- it only knows about this when it
gets evaluated.
Within the matcher we do have access to the current context class, so we
could read the subject block off of it and evaluate it. However, in
order to properly do this we also need access to the instance of the
test itself, which we do not have until the matcher is evaluated (by
which point it's too late).
Since there's really no way to solve this problem apart from rewriting a
lot of shoulda-context, and since often times your subject is an
instance and not a class, just assume it's an instance in this case.
This provides a robust solution for temporarily stubbing (and
unstubbing) methods. It will be internally by the strong parameters and
delegation matchers.
Under Minitest 5 (or a Rails 4.1 project), you will get a warning
MiniTest::Unit::TestCase is now Minitest::Test.
when you attempt to run tests. This is because shoulda-matchers requires
'test/unit/testcase', even if Test::Unit is not being used.
It is not a good idea for shoulda-matchers to require *anything* that
the user may not be using, whether it's Test::Unit or RSpec. We should
assume that by the time shoulda-matchers is required, the user has
already required all of whatever test framework they are using, not none
or even some of that framework.
Currently, using `ensure_inclusion_of` against a boolean column doesn't
work. We can assert that the column allows boolean values, but what
about values that should be rejected? Well, it depends on what you give
to `ensure_inclusion_of`. Here's how it works now:
* `ensure_inclusion_of(:attr).in_array([true])` asserts that false is
rejected
* `ensure_inclusion_of(:attr).in_array([false])` asserts that true is
rejected
* `ensure_inclusion_of(:attr).in_array([true, false])` does not assert
that anything is rejected, instead informing the developer how
this sort of expectation is not fully testable (anything other than
true, false, or nil will be converted to false).
* `ensure_inclusion_of(:attr).in_array([nil])`, when the column is
nullable, does not assert that anything is rejected, either, also
printing a warning
* `ensure_inclusion_of(:attr).in_array([nil])`, when the column is
non-nullable, raises an error because this expectation is not testable
in any way, as setting a boolean column to nil this way will get
converted to false.
Rails 4 moved the layouts ivar from `@layouts` to `@_layouts`.
This change introduces what I have (for now) called the 'RailsShim'. The
idea is that this single class will house the rail version workarounds,
which can then be reused through the code. This paid off here because
both the spec and the implementation need access to the layouts ivar.
An edge case occurs when mixing RSpec and Test::Unit tests and also
loading both the 'rspec-rails' gem and 'shoulda-matchers' gem from the
same Gemfile group, namely [:test, :development] . Work around this by
always inserting the shoulda matchers into Test::Unit, regardless of
whether RSpec is loaded.