Testing In Rails: Unit Testing In Models
Hi friends,
In my previous blog, Testing In Rails: Introduction and Creating Test Data, I had given you a brief introduction of rails test cases and why they are required. Also I guided you how we can create test data using factory girls or fixtures, which will be used in testing our application related methods. Now its time to see how we can write test cases.
Unit Testing in Models:
Rails is a proper MVC framework, where models represents the classes which are used for associating with the database. Thus most of the business logics, validations are performed in the models. It means they have the most highest priority for testing. In this blog we are using Unit test cases for testing the application. For testing the model properly, these things needs to be checked:
a) whether a valid data is going into the database - validations
b) all associations are working properly - associations
c) all callbacks are working properly - callbacks
d) all class methods are working properly
e) all object methods are working properly
Now to understand the functionality of test cases, lets first create a model Product with a title, description and price.
rails g model Product title:string description:text price:decimal
# =>
invoke active_record
create db/migrate/20160624173932_create_products.rb
create app/models/product.rb
invoke test_unit
create test/models/product_test.rb
create test/fixtures/products.yml
Now closely look the test/models/product_test.rb, which will look like:
require 'test_helper'
class ProductTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end
The code require 'test_helper' specifies that whatever thing is written inside the test_helper.rb is available in all the model test files. There are basically two ways of writing a test stubs, one sample which is already written above like specifying a test keyword with a string and creating a block of that, the other is create a method starting with test_ prefix:
# Using Block
test "validation method" do
# Your code Here
end
# Using Method
def test_validation_method
# Your code Here
end
After this the next section is how we can check, whether a method in a model is working fine. For that there must be some desired output for a set of input. For that kinds of validations there are assertions, which are used for the following tasks:
a) expected output value = actual output value
b) whether the object is nil?
c) whether there is exception in a line of code.
For these kinds of checking we have assertions. Assertions are actually used for evaluating the object or output for its desired expected result. So our test case can have more than one test cases depending upon the requirement. A method is said to pass the test only if none of the assertions gets failed. There are so many kinds of assertions available in ruby and rails. Full list of assertions can be found here:
http://ruby-doc.org/stdlib-2.1.1/libdoc/test/unit/rdoc/Test/Unit/Assertions.html
http://api.rubyonrails.org/classes/ActiveSupport/Testing/Assertions.html
Now lets test our first model but Before testing that lets add a validation in the Product model.
class Product < ActiveRecord::Base
validates :title, presence: true
end
Now lets create test cases for this models validation using assertions
require 'test_helper'
class ProductTest < ActiveSupport::TestCase
test "validations in product model" do
product = Product.new(title: '', description: 'Great Going', price: 1000)
assert_equal false, product.save, 'Product should not be created because title is not present'
product = Product.new(title: 'Product Title', description: 'Great Going', price: 1000)
assert_equal true, product.save, 'Product should be created'
end
end
After that finally run the test case using:
bin/rake test test/models/product_test.rb
#=>
Run options: --seed 271
# Running:
.
Finished in 0.275001s, 3.6363 runs/s, 7.2727 assertions/s.
1 runs, 2 assertions, 0 failures, 0 errors, 0 skips
Now looking into the output, we can see that we have run one test stub for which there were two assertions in which both passed so the failure is o and also the code doesn't contain any error so errors are also 0.
The dot (.) below the running expressed the pass of the test stubs. It will show F in case of failure and E in case of errors. Also one more thing to be noticed of how we should write assertions, after the assert keyword we should write the expected value and after that there should be the actual value and a assertion message to differentiate the case, separated by commas. After that lets change a little bit code in the test file to check the failed case
require 'test_helper'
class ProductTest < ActiveSupport::TestCase
test "validations in product model" do
product = Product.new(title: '', description: 'Great Going', price: 1000)
assert_equal false, product.save, 'Product should not be created because title is not present'
product = Product.new(title: 'Product Title', description: 'Great Going', price: 1000)
assert_equal true, product.save, 'Product should be created'
end
end
Now again run the test case:
bin/rake test test/models/product_test.rb
#=> Now it will give the output
Run options: --seed 40450
# Running:
F
Finished in 0.175340s, 5.7032 runs/s, 5.7032 assertions/s.
1) Failure:
ProductTest#test_validations_in_product_model [/home/raghvendra/rails_apps/MyTestingApp/test/models/product_test.rb:6]:
Product should not be created because title is not present.
Expected: true
Actual: false
1 runs, 1 assertions, 1 failures, 0 errors, 0 skips
Thus we can see the assertion failed here showing the failed the assertion message. The test case should contain all possible types of input data sets and conditions to get rid of later bugs.
Hope you liked this in next chapter I will talk about how we can write test cases for controllers.
Testing In Rails: Functional Testing In Controllers
0 Comment(s)