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

WIP: Add converting_values to validation matchers #820

Closed
wants to merge 3 commits into from

Conversation

mcmire
Copy link
Collaborator

@mcmire mcmire commented Oct 26, 2015

This is WIP as I add tests for every matcher to which this applies.

I don't like the idea of blindly ignoring any CouldNotSetAttributeError that may arise from using a particular matcher. It may very well be that the exception could be raised for a good reason. So instead of doing this, I'm proposing a new matcher: converting_values (or its companion, converting_value_to, for allow_value). The idea here is that you give the matcher a whitelist of acceptable values and their converted forms. So if the matcher detects a CouldNotSetAttributeError, but the value it sent to the attribute and the value it got out are both in this whitelist, then it'll ignore the exception and move on.

I think this is preferable over supplying some kind of lambda (which I proposed in #799) because at that point you'd probably be copying or recreating the same logic you have in the model. I think that by explicitly listing the acceptable values it's far easier to control and it's more clear to someone reading the test what's going on.

  • numericality
  • absence
  • acceptance
  • confirmation
  • exclusion (producing a test case here is difficult)
  • inclusion (producing a test case here is difficult)
  • length
  • presence (the only thing that's set on the record is nil, and we are handling value conversions here so as long as the final value is blank)
  • uniqueness (this actually creates a lot of problems so we should probably raise a specific error?)

it 'accepts (and not raise an error)' do
model = define_model_validating_uniqueness(
attribute_name: :name,
validation_options: { case_sensitive: false }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put a comma after the last parameter of a multiline method call.

We now always run the absence tests since we don't support anything
before Rails 4, so there's no need for a conditional.
* For some reason, ActiveRecord was printing a warning saying that
  "active_record/base" was already being loaded and there was a possible
  circular dependency. We fix this by explicitly requiring
  "active_record/base" before `$VERBOSE` is set to true.
* We were getting warnings when re-defining Kernel.capture,
  Kernel.silence_stream and Kernel.silence_stderr, so undefine them
  first.
More commit message here...
@mcmire mcmire force-pushed the ew-add-cast-with-to-validation-matcher branch from 7fa233a to 830b38c Compare October 28, 2015 05:55
converting_values(
'xxx' => 'XXX',
'xxxx' => 'XXXX',
'xxxxx' => 'XXXXX'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put a comma after the last parameter of a multiline method call.

expect(record).
to validate_length_of(:name).
is_at_least(0).
converting_values("x" => "X")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer single-quoted strings when you don't need string interpolation or special symbols.

@mcmire
Copy link
Collaborator Author

mcmire commented Nov 20, 2015

After thinking about it, I'm not sure I like this approach -- if you have a test that uses a factory to build a record, and a value for the attribute being tested is provided within the factory itself, and the matcher fails because that value is getting changed somehow, it doesn't really make sense to use converting_values to fix that issue, because you'll have this value that's referred to in the test out of context.

In other words, if you have this factory:

factory :user do
  username "some_username"
end

and this model:

class User < ActiveRecord::Base
  def username=(username)
    super(username.downcase)
  end
end

and you have this test:

describe User do
  context "validations" do
    it do
      create(:user)
      should validate_uniqueness_of(:username)
    end
  end
end

it wouldn't make sense to say:

describe User do
  it do
    should validate_uniqueness_of(:username).
      converting_values("SOME_USERNAME" => "some_username")
  end
end

because a reader of this test wouldn't even know where this comes from.

In fact, if you saw:

describe User do
  it do
    should validate_uniqueness_of(:username).
      converting_values("A" => "a")
  end
end

would you be confused where "A" is coming from? I might.

So, perhaps we do this instead:

@mcmire
Copy link
Collaborator Author

mcmire commented Dec 18, 2015

Closing this in favor of #866.

@mcmire mcmire closed this Dec 18, 2015
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

Successfully merging this pull request may close these issues.

2 participants