The ABC of Unit Testing in Rails, Part 1

Model Testing

Gary Cordero Rosa
5 min readFeb 1, 2021

As of recently, I’ve been increasingly testing my own code and as I said in my previous post I have learned so much more since I started doing it. I decided that I should share the riches of my gains and write about it,

**NOTE: Before proceeding, this article is meant to be used by a person that has some experience developing in rails since I would skip the environment installation and other technical aspects.**

Why unit testing? Because testing earlier and in small chunks makes it easier to detect errors that may result costly in the future but not only that, a developer learns so much from testing their codes like how to avoid repeating it, how to solve it if a similar issue arises, their coding bad habits, etc… Therefore learning to be more mind full of their code, and more experience at detecting errors, and more likely to write cleaner code avoiding the worst scenario.

Well without further ado, let’s start building our demo rails app and start testing. We will explore the base for testing a model class and we will write the unit test for it using the default rails testing gem Minitest.

  1. Create a react app.
rails new unit-testing

2. Let's go into our rails app folder and generate our User model.

cd unit-testing
rails g model User name:string email:string age:integer

Now your folder should contain the user class in app/model/user.rb , the user class migration file in db/migrate/xxxxxxx_create_users.rb , and the user class test file in test/model/user_test.rb.

3. Run our migration rails db:migrate.

4.Let’s write our tests for user class but before that let's examine our class and think about the features that we want to test.

……..…..Tests List……………

  • The name and email should not be empty.
  • The name should be between 3 to 25 characters long.
  • The email should pass the standard email structure.
  • The user should be 18 years old or older.
  • User email must be unique.
  • The user should be able to add two numbers.

Testing

Now that we know what we want to test let’s write those unit tastes in the test/model/user_test.rb . One thing to be aware of is that the testing database is wiped every time you finish running the test, therefore there will be times where additional setups must be implemented before running the test. An example would be testing for User authentication since it would require a user to exist in the testing database prior to running that test.

Testing “name should not be empty”

test "Name should not be empty" do
@user.name = " "
assert_not( @user.valid?, "User was saved with a blank name")
end

The method assert_not() will pass if it receives a falsy value, now that we wrote the test we can run it with the command rails test or we can run a specific test by doing rails test path/to/test/file.rb.

As you can see our test failed because the model was valid with an empty name. Let’s fix that by adding validations to our model and making sure that the name must be present in order to be valid.

class User < ApplicationRecord
`````validates :name , presence: true
end

Testing “name should be at least 3 characters long ”

test "Name should be at least 3 characters" do
@user = User.new
@user.name = "aa"
assert_not(@user.valid?, "the name should no be that short" )
end

If we run the test.

Again we can fix that by adding validations to our model.

class User < ApplicationRecord
validates :name , presence: true, length: {minimum:3}
end

Testing “ Email should be unique”

test "Email must be unique" do
@user = User.create({name:"gary",email:"gary@aol.com"})
@user2 = User.new({name:"Jose",email:"gary@aol.com"})
assert_not(@user2.valid?, "the email must be unique" )
end

To pass the test we add validations

class User < ApplicationRecord
validates :name , presence: true, length: {minimum:3}
validates :email, uniqueness: true
end

Testing “ Email should match email standard pattern”

test "Email should match email standard pattern" do
@user = User.new({name:"Jose",email:"gar.aol.com"})
assert_not(@user.valid?)
end

Adding validations

class User < ApplicationRecord
validates :name , presence: true, length: {minimum:3}
validates :email, uniqueness: true, format: {with:/[\w-]+@([\w-]+\.)+[\w-]+/, message: "Not email compliant" }
end

Testing. “the user should be able to add two numbers”

test "the user should be able to add two numbers" do
@user = User.new
assert_equal(@user.add(1,2),3,"The user should know basic math")
end

To pass this one we just got to define the method add() in the user class

class User < ApplicationRecord
validates :name , presence: true, length: {minimum:3}
validates :email, uniqueness: true, format: {with: /[\w-]+@([\w-]+\.)+[\w-]+/, message: "Not email compliant" }
def add(a,b)
a + b
end
end

Conclusion

Testing is essential because it helps you to build robust code from an early stage and forces you to validate every part of your close, therefore making you a better developer. As a bonus, there is still a validation that I have not done yet “The user should be 18 years old or older” if you like the post I encourage you to leave what you believe would be the code for the test case in the comments.

--

--

Gary Cordero Rosa
Gary Cordero Rosa

Written by Gary Cordero Rosa

Flatiron School Software Engineering Student

No responses yet