Unit Testing in Ruby
Unit testing is a basic software development technique that ensures accuracy both now and in the future by concentrating on small, discrete pieces (or “units”) of code, usually individual lines or functions. Because unit testing gives you immediate feedback on how correct your code is, it focusses on identifying and resolving issues early ideally before they have an impact on anybody.
Key Concepts of Unit Testing
Unit Tests vs. Other Tests: In contrast to other types of testing that look at the system as a whole, unit testing does only that.
Test-Driven Development (TDD): The Ruby community encourages Test-Driven Development, or TDD, which involves developing automated tests either concurrently with or even before to writing the related functionality. This compels developers to establish the intended behaviour of classes and methods, categorize troublesome use cases, and conduct in-depth problem analyses.
Benefits: You may confidently change and reorganize your code with automated tests since they will detect any issues right away if something goes wrong. They also act as a guide for other patrons of your library.
You can also read What Is Debugging In Ruby With Pry/Byebug with Code Example
How to write unit tests in Ruby?
To write a test, follow these steps:
- Make sure Test::Unit is in your library path.
 - Require ‘test/unit’ in your test script.
 - Create a class that subclasses Test::Unit::TestCase .
 - Add a method that begins with “test” to your class.
 - Make assertions in your test method.
 
The Test::Unit Framework
The testing framework, Test::Unit, is preloaded and part of the standard Ruby library. It offers three primary capabilities: a means of expressing individual tests, a framework for arranging them, and adaptable methods for calling them.
In order to utilize Test::Unit, you typically take these actions:
Require the framework: Include require 'test/unit' and the class you intend to test.
Define a Test Case: Create a class that inherits from Test::Unit::TestCase.
Define Test Methods: Each actual test must be written as a method within the test class, and its name must begin with the prefix test.
Use Assertions: You make assertions inside these methods, which are necessary for the code to be correct.
You can also read What Is Duck Typing In Ruby With Practical Code Examples
Code Example: Testing the Person Class
Examine the following basic Person class, which has a name and age:
# app/person.rb
class Person
  # Allows reading and writing of attributes
  attr_accessor :first_name, :last_name, :age
  
  def initialize(first_name, last_name, age)
    # Basic validation in the constructor
    raise ArgumentError, "Invalid age: #{age}" unless age > 0 
    
    # Corrected line: All instance variables must start with @
    @first_name, @last_name, @age = first_name, last_name, age 
  end
  
  def full_name
    first_name + ' ' + last_name
  end
end
Output
--- Person Details ---
Full Name: Govindhtech
Age: 3
New Age: 4
You can also read IRB In Ruby: Instant Coding With The Interactive Shell
You would make a matching file, such as test/person_test.rb, to test this class:
# app/person.rb
class Person
  attr_accessor :first_name, :last_name, :age
  
  def initialize(first_name, last_name, age)
    # Basic validation in the constructor
    raise ArgumentError, "Invalid age: #{age}" unless age > 0 
    
    # Corrected Instance Variable Assignment
    @first_name, @last_name, @age = first_name, last_name, age 
  end
  
  def full_name
    "#{first_name} #{last_name}"
  end
end
# --- Execution Code to Generate Output ---
# 1. Create a valid Person object
person1 = Person.new("Grace", "Hopper", 85)
# 2. Call the full_name method and print the result
puts "--- Person Details ---"
puts "Full Name: #{person1.full_name}"
puts "Age: #{person1.age}"
# 3. Demonstrate the error-checking
puts "\n--- Demonstrating Validation ---"
begin
  Person.new("Zero", "Age", 0)
rescue ArgumentError => e
  puts "Error caught: #{e.message}"
end
Output
--- Person Details ---
Full Name: Grace Hopper
Age: 85
--- Demonstrating Validation ---
Error caught: Invalid age: 0
Core Assertions
There are many assertion techniques available in Test::Unit:
| Assertion | Purpose | Example | 
| assert(boolean) | Fails if the boolean condition is false or nil. | assert(expected == actual) | 
| assert_equal(expected, actual) | Expects actual to match expected using ==. | assert_equal 'Nathaniel', person.first_name | 
| assert_raise(Exception) | Expects the block to raise one of the listed exceptions. | assert_raise(ArgumentError) { ... } | 
| assert_nil(obj) | Expects the object to be nil. | assert_nil(list) | 
| assert_kind_of(klass, obj) | Expects obj to be a kind (instance or subclass) of klass. | assert_kind_of User, users(:first) | 
| assert_match(regexp, string) | Expects string to match the regular expression. | assert_match(/krauss/i, entry.artist) | 
| assert_nothing_raised() | Expects the block to execute without raising exceptions. | assert_nothing_raised() { Roman.new(1) } | 
Since assert may be used to define all other assertions, it is the most fundamental statement.
You can also read Ruby Enumerable Module: Essential Methods Every Developer
Structuring and Running Tests
Setup/Teardown: Define a setup method that runs before each test method and a teardown method that runs after each test method to allow for cleaning and eliminate repeated setup code (such as generating a Person object in each test).
Running Options: You may use the script’s –name option to perform particular tests. To select methods, the –name option can optionally utilize a regular expression (for example, –name ‘/test_f/’ to run methods that begin with test_f).
Unit tests function as a powerful, automated foundation inspector by offering quick and detailed validation. This way, you can quickly determine if the foundation of your earlier work is still sound each time you add a new wall (code feature).
