Ruby Exception & Testing
Objetives

Exceptions
A special kind of object, an instance of the class Exception or a descendant of that class, indicates that something has gone wrong.

Exception flow

-
When something fails, an exception is raised -thrown-.
-
By default, Ruby programs terminate when an exception occurs.
-
A block of code can be executed as a handler -exception handler- if an exception raises during the execution of some other block of code.
-
Raising an exception means stopping the normal execution of the program and transferring the flow-of-control to the exception handling code -deal with the problem or exit the program completely-.
-
The consequent action depends on whether you have provided a rescue clause.

Exception methods
| Method | Description |
|---|---|
| Exception#class | Returns the class of the receiver |
| Exception#backtrace | Returns the backtrace of the error |
| Exception#message | Returns the error message. |
| Kernel#raise | Raise an error |


class MaybeError < StandardError
attr_reader :limit
def initialize(message, limit)
super(message)
@limit = limit
end
end
def maybe_error(number)
limit = rand(1..10)
message = "Error for number #{number} when limit is #{limit}"
raise MaybeError.new(message, limit) if number < limit
end
number = 1
count_retry = 0
retry_limits = 3
begin
count_retry += 1
maybe_error(number)
rescue MaybeError => error
puts "#{error.message} recued!"
puts "Limit variable on maybe_error method => #{error.limit}"
number += 1
# count_retry <= retry_limits ? retry : raise
if count_retry <= retry_limits
retry
else
puts "Too many Retries!! retries number #{count_retry}"
end
ensure
puts "This is always executed!"
end
puts "All is OK when number was #{number}" # show!

Exceptions Code
Unit testing
Ensures that all code meets quality standards before it's deployed. Over the course of the product development life cycle, saves time and money, and helps developers write better code, more efficiently.

Why Minitest

-
Simple
-
Easy to learn
-
Good TDD workflow
-
Randomized by default
-
Fast
Stages of a test

- Setup
- Execution
- Assertion
require 'minitest/autorun'
class RelatedClassTest < Minitest::Test
def test_ask_for_functionality
# setup
declare_variables
declare_expectations
# execution
create_instances
do_calculations
call_methods
# assertion
assert
assert_equal expected, result
assert_nil result
assert_empty object
assert_includes collection, object
assert_match pattern, object
assert_raises(Error) { method }
end
end
Implementation
Exercise

# frozen_string_literal: true
module Pokedex
CATALOG = {
bulbasaur: {
type: ["grass", "poison"],
weaknesses: ["fire", "psychic", "flying", "ice"]
}
}.freeze
end
# Pokemon test class to apply unit testing on it
class Pokemon
include Pokedex
attr_reader :species, :name, :level, :type, :weaknesses, :hp
attr_accessor :current_move
def initialize(species:, name:, level: 1)
raise StandardError, 'species and name could not be empty' if species.empty? || name.empty?
properties = Pokedex::CATALOG[species.to_sym]
@species = species
@name = name
@type = properties[:type]
@weaknesses = properties[:weaknesses]
@level = level
@max_health = 100
end
def prepare_for_battle
@hp = @max_health
@current_move = nil
end
def receive_damage(damage)
@hp -= damage
end
def fainted?
!hp.positive?
end
end
# species = "bulbasaur"
# name = "Bulbi"
# level = 1
# pokemon = Pokemon.new(species: species, name: name, level: level)
# p pokemon

pokemon.rb
require 'minitest/autorun'
require_relative "pokemon"
class PokemonTest < Minitest::Test
def test_create_a_new_pokemon
# Setup
species = "bulbasaur"
name = "Bulbi"
level = 1
# Execution
pokemon = Pokemon.new(species: species, name: name, level: level)
# Assertion
assert_instance_of(Pokemon, pokemon)
# assert_equal("Bulbi", pokemon.name)
end
def test_pokemon_properties
# Setup
species = "bulbasaur"
name = "Bulbi"
level = 1
type = Pokemon::CATALOG[:bulbasaur][:type]
weaknesses = Pokemon::CATALOG[:bulbasaur][:weaknesses]
# Execution
pokemon = Pokemon.new(species: species, name: name, level: level)
# Assertion
assert_equal("Bulbi", pokemon.name)
assert_equal("bulbasaur", pokemon.species)
assert_equal(level, pokemon.level)
assert_nil(pokemon.current_move)
assert_nil(pokemon.hp)
end
def test_raise_error_when_name_is_empty
# Setup
species = "bulbasaur"
name = ""
level = 1
# Assertion
assert_raises(StandardError) do
Pokemon.new(species: species, name: name, level: level)
end
end
def test_raise_error_when_species_is_empty
# Setup
species = ""
name = "Bulbi"
level = 1
# Assertion
assert_raises(StandardError) do
Pokemon.new(species: species, name: name, level: level)
end
end
def test_prepare_for_battle
# Setup
species = "bulbasaur"
name = "Bulbi"
level = 1
pokemon = Pokemon.new(species: species, name: name, level: level)
# Execution
pokemon.prepare_for_battle
# Assertions
assert_equal(100, pokemon.hp)
assert_nil(pokemon.current_move)
end
def test_pokemon_receive_damage
#
end
def test_pokemon_fainted
#
end
end
testing.rb
Ruby Exceptions & Testing
By Paulo Tijero
Ruby Exceptions & Testing
- 112