user5060176
user5060176

Reputation:

How minitest testing framework works in rails?

I just started to learn testing with minitest but it sounds very confusing to me. What does this statement means?

test 'should not save simulations without name' do
 post = Post.new
 assert !post.save, 'Saved the simulations without a name'
end

Post Model

class Post < ActiveRecord::Base
  validates_presence_of :name , :type
  belongs_to :user
  before_create :check_validation
  validates :type,  :inclusion => { :in => 1..10, :message => 'The row must be between 1 and 10' }

 private
 def check_validation(data, type)
  ....
 end

What would be the minitest method for following conditions:

I have already created post.yml file and user.yml file. How to proceed again. I tried to read ruby official documentation but it is not very helpful.

Thanks in adnvance

Edit 1

my yml file

one:
  name: 'test'
  type: 3
  user_id: 1

I tried :

test 'Post must have all parameters' do
assert assigns(:one).valid?

end

Upvotes: 5

Views: 800

Answers (2)

Chris Kottom
Chris Kottom

Reputation: 1289

check if name, type parameter exist when creating a new object of Post class. How can I do it post_test class?

Is this test method are checking the presence of name in post?

Sort of. The assertion checks that saving the new Post instance fails, but there are several reasons for that result - e.g. missing :name and :type attributes, the before_create filter that could hijack the save operation.

If you want to test each of these validations individually, you'll want to start with a known valid Post record and manipulate it to trigger each validation to fail. Usually, I'll have at least one minimally valid record set up in my fixture file - in this case, I'll call it :mvp. Ex:

test 'MVP is valid' do
  assert posts(:mvp).valid?, 'Minimum valid Post is invalid'
end

test 'should not save simulations without name' do
  post = posts(:mvp)
  post.name = nil
  assert post.invalid?, 'Post is valid without a name'
end

...

For the most part, I find that testing simple validations (presence, simple numericality, etc.) clutters my tests and smells a little like testing the framework instead of my own application code, so I'll often skip them.

How can I test check_Validation through PostTest class?

check_validation is marked as a private method, and in general, you don't want to directly test private methods. You can, however, verify that the conditions you set on newly created models match your expectations:

test 'newly created Post has settings XYZ' do
  post = Post.new(...)
  assert post.save, 'Post could not be saved'
  # assertions to test #check_validations side effects here...
end

You don't include the body of your check_validation method, so I don't know what you've got in mind here. With a name like that though, I'm inclined to believe you're trying to do some kind of validation that would be better left to a custom validation method defined using the validate method. See the docs to see whether it applies in your case.

How to check throw error if posts is not belong to users?

I'd make this a validated condition on your Post class as:

class Post
  belongs_to :user
  validates  :user, presence: true
end

Hope that helps somewhat. I've tried to answer your questions in a way that will let you get on with your work, but if you're interested in learning to be productive with Rails and Minitest, you're going to want to do a deeper study of the framework and how it's used with Rails.

Upvotes: 1

blowmage
blowmage

Reputation: 8984

This is a poorly written test, so I can see why you are confused. I assume that there is a companion test that attempts to show that the Post can be saved when it has a name.

test 'should save simulations with name' do
  post = Post.new name: 'simulator McSimulation'
  assert post.save, 'Must save the simulations with a name'
end

test 'should not save simulations without name' do
  post = Post.new
  assert !post.save, 'Saved the simulations without a name'
end

What does this statement means?

That is a test method. In Minitest there are three main concepts: test class, test method, and assertion method.

Test Class

A test class is a class that inherits from Minitest::Test. It can inherit from it directly:

class PostTest < Minitest::Test
end

Or it can inherit from it indirectly

class ActiveSupport::TestCase < Minitest::Test
end

class PostTest < ActiveSupport::TestCase
end

All the testing behavior we use is available because we are creating test classes.

Test Method

A test method is a method that begins with test_, like this:

class PostTest < ActiveSupport::TestCase
  def test_valid
    # do the testing here
  end
end

Rails adds some syntax sugar so that test methods can be created by passing a string and block to the test method instead:

class PostTest < ActiveSupport::TestCase
  test "is valid" do
    # do the testing here
  end
end

Your statement is using the rails-specific syntax. All test methods in a test class are run by Minitest.

Assertion method

The test class and test methods are how you structure the test, the assertion method is how you actually do the testing. The most basic way to indicate the code behaves as expected is to pass a truthy value to assert, and an optional description to give guidance if the value is ever falsey. This is what your statement is doing. Post#save returns a value, which you are negating, and then passing to assert.

Minitest defines many more assertion methods.

Improving the test

I said this was a poorly written test. What do I mean by that? Well, first off, the assertion could fail for any number of reasons, so this test isn't as specific as it needs to be. Here are some changes I would make:

1) The refute method is the invert of assert, so I would use refute value instead of assert !value.

test 'should not save simulations without name' do
  post = Post.new
  refute post.save, 'Saved the simulations without a name'
end

2) Calling save actually sends the data to the database, which is slow and should be avoided when possible. Use valid? instead of save.

test 'must not be valid without name' do
  post = Post.new
  refute post.valid?, 'Must be invalid without a name'
end

3) Make sure the reason the model isn't valid is because of the reason for the test, specifically that it needs a name. There are several reasons this model is invalid, and would not be saved. We need to be more specific here. The best way to specify this IMO is to check that the model's errors object includes a reason for the missing name.

test 'must not be valid without name' do
  post = Post.new
  refute post.valid?, 'Must be invalid without a name'
  assert post.errors[:name].any?, 'Must be invalid for missing name'
end

Of course we can make that even more specific by specifying a value returned by post.errors[:name]. Let's use the assert_includes assertion method that asserts that the collection contains a specific value:

test 'must not be valid without name' do
  post = Post.new
  refute post.valid?, 'Must be invalid without a name'
  assert_includes post.errors[:name], "can't be blank",
                  'Must be invalid for missing name'
end

Hope that helps.

Upvotes: 3

Related Questions