Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Ruby

Question about tests

I'm new to this, but have really been enjoying the Rails track to making a simple app.

So far it all actually makes quite a bit of sense, and then idea of testing is fascinating and much more intuitive than I would have guess.

I'm a little confused though, and I'll see if I can explain why:

When creating integration tests for the status controller, I can get this work pass, but I don't know why it SHOULD.

In /test/functional/status_test.rb this test is hurting my head:

test "that a status's content is at least 2 letters" do
status = Status.new
status.content = "H"
assert !status.save
assert !status.errors[:content].empty?
end

The corresponding validation in the status model:

validates :content, presence: true,
                  length: { minimum: 2 }

I understand the validation and how the minimum is being set, but I don't think I've fully understood the test.

In my mind, that test should fail, because it's passing a status with a 1 character content. Should it not fail at the .save?

Does anyone follow my logic and see why I don't understand the test portion? What is the test actually doing?

I can try to explain more if I need to

2 Answers

You're right that the validation will fail, the test however will pass.

  1. test "that a status's content is at least 2 letters" do
  2. status = Status.new
  3. status.content = "H"
  4. assert !status.save
  5. assert !status.errors[:content].empty?
  6. end

Line '4' calls the save method on the status object we create on line '2', this method will return true or false depending on whether the save process succeeds or fails. This process may fail if, for example, the status' content doesn't pass any validations. The bang operator (!) is then applied to the return value of the save method. !status.save will be true if the save method returns false, and !status.save will be false if the save method returns true. You might want to read (!) as NOT.

The assert method is passed the value of !status.save, and makes sure the value it is passed is true. The test on line '4' passes because the status' content fails the validation which causes the save method to return false which, once negated by the bang operator, is passed to assert method as true. So line '4' works.

Line '5' is in a similar vain. You access the errors property on the aforementioned status object and check to see if there are any errors pertaining to the status. Since 'status.errors[:content].empty?' will be true if there aren't any errors '!status.errors[:content].empty?' will be true if there ARE errors. Since we failed the validation there will definitely be errors, which is what we want.

Thanks so much, Aaron!

That makes sense, I wasn't thinking about the bang operator kicking out a false, but that makes sense.

What is the reasoning behind testing with the false/false (using the bang operator)? Why in the functional tests are we asserting for the true response?