Mocks & Stubs & Exceptions in Ruby

What are mocks and stubs?

Eliminate dependencies on other classes in testing

class Connection

attr_reader :status_code

def initialize
@status_code = get_service_status
end

def get_service_status
200
end

def connect_to_external_service(srvc)
return srvc.status_code
end

end
class ConnectionTest < Minitest::Test

def test_initializes_with_response_code
c = Connection.new
assert_equal 200, c.status_code
end

end
class Connection

attr_reader :status_code

def initialize
@status_code = get_service_status
end

def get_service_status
200
end


def connect_to_external_service(srvc)
return srvc.status_code
end

end

# this is my third-party class that `Connection` might have dependencies upon
class Service
attr_reader :status_code

def initialize
@status_code = get_service_status
# status_code would be 200, 504, 404, etc
end

def get_service_status
# do complicated stuff here to get status code
# return a status code
200
end
end
srvc = Service.new
conn = Connection.new

conn.connect_to_external_service(srvc)
class ConnectionTest < Minitest::Test

def test_connection_default_status_code_is_200
c = Connection.new
assert_equal 200, c.status_code
end

def test_external_service_default_status_code_is_200
conn = Connection.new
srvc = Service.new

assert_equal 200, conn.connect_to_external_service(srvc)
end
end

Stubbing the service object to force errors

def test_raises_error_when_service_returns_4xx_no_mocks
srvc = Service.new
srvc.status_code = 404
conn = Connection.new

assert_raises Connection::ServiceNotFound do
conn.connect_to_external_service(srvc)
end
end
1) Error:
ConnectionTest#test_raises_error_when_service_returns_4xx_no_mocks:
NoMethodError: undefined method `status_code=' for #<Service:0x00007f81ce3c34d8 @status_code=200>
require './lib/connection'
require 'minitest/autorun'
require 'mocha/minitest'

class ConnectionTest < Minitest::Test

def test_raise_error_when_service_returns_4xx_using_stubs
serv = Service.new
# instantiating a new Service object. if I call
# serv.status_code, it would return 200
Service.any_instance.stubs(:status_code).returns(404)
# override the method to always return 404
conn = Connection.new

assert_raises Connection::ServiceNotFound do
conn.connect_to_external_service(serv)
end
end

Mocking the service object

def test_rais_error_when_service_returns_4xx_using_mocks
conn = Connection.new
srvc = stub("srvc is now a stub.")
# srvc.class == Mocha::Mock

srvc.stubs(:status_code).returns(404)

assert_raises Connection::ServiceNotFound do
conn.connect_to_external_service(srvc)
end
end
mocked_object = mock('mocked_object')
stubbed_object = stub('stubbed_object')
> mocked_object
=> #<Mock:mocked_object>
> stubbed_object
=> #<Mock:stubbed_object>

Exceptions

def test_raise_service_timeout_if_service_returns_504
@srv.stubs(:status_code).returns(504)

assert_raises Connection::ServiceTimeOut do
@conn.connect_to_external_service(@srv)
end
end
def connect_to_external_service(srvc)
raise ServiceNotFound if srvc.status_code == 404
raise ServiceTimeOut if srvc.status_code == 504
# do other stuff
return srvc.status_code
end
.
.
def connect_to_external_service(srvc)
raise ServiceNotFound if srvc.status_code == 404
raise ServiceTimeOut if srvc.status_code == 504
# do other stuff
return srvc.status_code
end

class ServiceNotFound < StandardError; end
class ServiceTimeOut < StandardError; end
end
ServiceNotFound.ancestors
=> [Connection::ServiceNotFound,
StandardError,
Exception,
Object,
Kernel,
BasicObject]
StandardError.ancestors
=> [StandardError,
Exception,
Object,
Kernel,
BasicObject]

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store