0.0
No commit activity in last 3 years
No release in over 3 years
Write object protocols instead of message expectations.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

 Project Readme

ObjectProtocol

Table of Contents
  • Goals
  • What’s An Object Protocol?
  • Using Object Protocols
    • A Simple Logger
  • How Does This All Work, Anyway?
    • Interaction with #method_missing
  • Installation
  • Development
  • Contributing
  • Code of Conduct

Goals

  1. Write message expectation tests with less boilerplate than when using RSpec spies

  2. Resulting protocols should be usable as documentation

  3. Be able to specify which object sent the message and which object received it (traditional message expectation test only allow the latter)

What’s An Object Protocol?

Protocols are the types of an OO program. They structure and order the messages passed between communicating agents.

Using Object Protocols

A Simple Logger

Given a unrealistically simple logger:

class UnrealisticLogger
  def initialize(device)
    @device = device
  end

  def log(message)
    @device << message
  end

  def rotate
    @device.shift
  end
end

we can write a protocol for what happens when we call #log on an instance of UnrealisticLogger

UnrealisticLoggingProtocol = ObjectProtocol.new(:device, :logger) do # (1)
  logger.sends(:<<).to(device) # (2)
end
  1. we need to tell the protocol the names of the participants

  2. we switch to using local variables here instead of the symbols

Then, we can test this protocol:

require 'object_protocol/rspec'

RSpec.describe UnrealisticLoggingProtocol do
  it "is satisfied by calling #log on the logger" do
    device = []
    logger = UnrealisticLogger.new(device) # (1)

    UnrealisticLoggingProtocol.bind( # (2)
      device: device,
      logger: logger,
    )

    expect(UnrealisticLoggingProtocol).to be_satisfied_by do
      logger.log("message") # (3)
    end
  end
end
  1. instantiate the participants

  2. bind participants to the protocol

  3. test an execution against the protocol

Ok, but what was all that?

Well, we created a protocol that we can use as documentation, and tested it with a lot less fanfare and boilerplate than you’d need with traditional message expectation tests!

In real life, you’d use an actual object defined in your codebase in place of a fake logger, but you’d probably inject fake or stub collaborator objects to avoid side-effects.

How Does This All Work, Anyway?

During an execution (the block passed to satisfied_by), we spy on every public method (except #send and #object_id because of the warnings) defined on each bound participant object. We record the message, the sender, the receiver, and the arguments (if any) that were passed. Then, we invoke the actual method behavior defined by that object.

Interaction with #method_missing

#method_missing is rarely a message that is sent from one object to another. We currently record the name of the missing method as the "sent message" and record any arguments beyond that message name, as well as the sender and receiver.

Installation

Add this line to your application’s Gemfile:

gem 'object_protocol'

And then execute:

$ bundle

Or install it yourself as:

$ gem install object_protocol

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/yarmiganosca/object_protocol. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

Code of Conduct

Everyone interacting in the ObjectProtocol project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.