I've iterated on my design a bit, and for now have settled on this version
which lets me replace two assertions in my test:
def assert_model_error(*args, **opt, &block)
attribute, pattern = args.count == 1 ? [ nil, args[0] ] : args
e = assert_raises(Sequel::HookFailed, Sequel::ValidationFailed, **opt, &
block)
if e.respond_to?(:errors)
errors = attribute.blank? ? e.errors.full_messages : Array(e.errors.on
(attribute)) # convert nil to empty array
else
errors = Array(e.message)
end
assert_match pattern, errors.join("\n"), **opt
end
Which then allows me to do this:
assert_model_error(:password, /present/) do
User.create(username: 'testuser')
end
assert_model_error(/cannot delete last email/) do
@last_email.destroy
end
The reason I'm catching HookFailed in addition to ValidatedFailed is
because some validations (like not allowing a user to delete his last email
address, thereby ensuring they always have at least one) can't be
implemented in validate() because validate isn't called in all cases (like
Model#destroy). So I've been using hook methods for those validations and
using cancel_action(message) to trigger a HookFailed exception.
PS-I'm a noob, so if I'm doing something stupid here (or there's simply a
better way), please chime in.
-ofer
On Monday, October 5, 2015 at 8:20:26 PM UTC-4, Ofer Nave wrote:
>
> I finally started writing tests for my models today (new to sequel, just
> finished adding a test framework to my new app), and I thought of a need
> for a helper -- which means I can now contribute something other than just
> criticism. :)
>
> I'm using assert_raises to ensure that saving an invalid model raises a
> Sequel::ValidationFailed, and to be thorough, I also want to make sure I
> get the right error message on the right field. But because
> errors.on(:field) can either return nil or an array, I needed to do it in
> two steps:
>
> def test_username_validations
> e = assert_raises(Sequel::ValidationFailed) { User.create(password:
> 'pw') }
> refute_nil e.errors.on(:username)
> assert_match /too short/, e.errors.on(:username).join("\n") unless
> e.errors.on(:username).nil?
> end
>
> That's ugly and tedious. So I added a method to my test base class:
>
> def assert_error(errors, pattern)
> refute_nil errors
> assert_match pattern, errors.join("\n") unless errors.nil?
> end
>
> And call it like this:
>
> def test_username_validations
> e = assert_raises(Sequel::ValidationFailed) { User.create(password:
> 'pw') }
> assert_error e.errors.on(:username), /too short/
> end
>
> Which looks *way* better. Though there's plenty of room for improvement
> -- I bet the error messages when "refute_nil errors" fails isn't too
> useful, other than the line number.
>
> -ofer
>
> On Monday, October 5, 2015 at 11:36:35 AM UTC-4, Ofer Nave wrote:
>>
>> Not to be a downer, but... while I like the idea of a minitest-sequel
>> helper, I'm don't find those assertions particularly helpful. It seems
>> like you're just duplicating the migrations and model validation statements
>> in test form. I guess it would protect you from someone accidentally
>> deleting a validation in a model, but it creates a lot of extra work
>> (keeping the tests in sync with schema and validation changes, and will
>> probably result in copy/paste from models in practice, which means errors
>> in defining the validation will be inherited in the tests).
>>
>> What I might find useful is a way to make it easier to test custom
>> validations and hook behavior, since that's where I'm writing my own code
>> that could use tests, as opposed to simply calling the built-in validates_*
>> methods (which are already tested in the sequel gem, and for which the
>> syntax is intuitive and well-defined).
>>
>> -ofer
>>
>> On Tuesday, September 22, 2015 at 8:04:35 AM UTC-4, Kematzy wrote:
>>>
>>> Hi,
>>>
>>> I just released *Minitest-Sequel* [
>>> https://github.com/kematzy/minitest-sequel ], a collection of
>>> convenient assertions for testing common Sequel features with Minitest.
>>>
>>> It is still very much work in progress, so please feel free to assist in
>>> improving or adding to this gem. *Especially if you can work out how to
>>> test Sequel validations in Minitest.*
>>>
>>> Any help will be gratefully received.
>>>
>>>
>>> Included assertions are:
>>>
>>> *- TABLE DEFINITIONS:*
>>>
>>> -- assert_have_column()
>>>
>>>
>>> *- ASSOCIATIONS:*
>>>
>>> -- assert_association_one_to_one()
>>>
>>> -- assert_association_one_to_many()
>>>
>>> -- assert_association_many_to_one()
>>>
>>> -- assert_association_many_to_many()
>>>
>>> -- assert_association()
>>>
>>>
>>> *- VALIDATIONS:* (work in progress and not working)
>>>
>>> -- assert_validates_presence()
>>>
>>> -- assert_validates_exact_length()
>>>
>>> -- assert_validates_length_range()
>>>
>>> -- assert_validates_max_length()
>>>
>>> -- assert_validates_min_length()
>>>
>>> -- assert_validates_format()
>>>
>>> -- assert_validates_includes()
>>>
>>> -- assert_validates_integer()
>>>
>>> -- assert_validates_not_string()
>>>
>>> -- assert_validates_numeric()
>>>
>>> -- assert_validates_unique()
>>>
>>>
>>>
>>> *Test Examples:*
>>>
>>> let(:m) { Post.first }
>>>
>>> # test model/table definition
>>> it { assert_have_column(m, :title, { type: 'string', db_type:
>>> 'varchar(255)', allow_null: :false }) }
>>> it { assert_have_column(m, :body, { type: 'string', db_type: 'text'}) }
>>>
>>> # test model associations
>>> it { assert_association_one_to_many(m, :comments) }
>>> it { assert_association_many_to_one(m, :author) }
>>> it { assert_association_many_to_many(m, :tags) }
>>>
>>> it { assert_association_one_to_one(m, :first_comment, { class: :Commment
>>> , order: :id }) }
>>>
>>>
>>>
>>> *USAGE:*
>>>
>>> $ gem install minitest-sequel
>>>
>>>
>>> In your project's *spec_helper.rb* or *test_helper.rb* file:
>>>
>>> require 'minitest/sequel'
>>> require 'minitest/autorun'
>>>
>>> ## add migrations and seeds
>>>
>>> require 'sqlite3'
>>>
>>> DB = Sequel.sqlite # memory
>>>
>>>
>>>
>>>
>>>
>>> Hopefully this will help someone.
>>>
>>>
>>>
--
You received this message because you are subscribed to the Google Groups
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sequel-talk.
For more options, visit https://groups.google.com/d/optout.