All Projects → jorgemanrubia → Impersonator

jorgemanrubia / Impersonator

Licence: mit
Ruby library to record and replay object interactions

Programming Languages

ruby
36898 projects - #4 most used programming language

Projects that are alternatives of or similar to Impersonator

ts-mock-imports
Intuitive mocking library for Typescript class imports
Stars: ✭ 103 (+3%)
Mutual labels:  mock, stub, fake
Stubmatic
Mock HTTP calls without coding. Designed specially for testing and testers.
Stars: ✭ 118 (+18%)
Mutual labels:  mock, stub, fake
stub-server
Stub server for REST APIs
Stars: ✭ 14 (-86%)
Mutual labels:  mock, stub, fake
Ohhttpstubs
Stub your network requests easily! Test your apps with fake network data and custom response time, response code and headers!
Stars: ✭ 4,831 (+4731%)
Mutual labels:  mock, stub
Fakerator
Random fake data generator with localization for Javascript in Node.js and browser
Stars: ✭ 91 (-9%)
Mutual labels:  fake, mock
Mimesis
Mimesis is a high-performance fake data generator for Python, which provides data for a variety of purposes in a variety of languages.
Stars: ✭ 3,439 (+3339%)
Mutual labels:  fake, mock
DeepfakeHTTP
DeepfakeHTTP is a web server that uses HTTP dumps as a source for responses.
Stars: ✭ 373 (+273%)
Mutual labels:  mock, stub
Clj Fakes
An isolation framework for Clojure/ClojureScript.
Stars: ✭ 26 (-74%)
Mutual labels:  fake, stub
Dyson
Node server for dynamic, fake JSON.
Stars: ✭ 814 (+714%)
Mutual labels:  mock, stub
Openapi Sampler
🔠 Tool for generation samples based on OpenAPI(fka Swagger) payload/response schema
Stars: ✭ 83 (-17%)
Mutual labels:  fake, mock
Mocha
Mocha is a mocking and stubbing library for Ruby
Stars: ✭ 1,065 (+965%)
Mutual labels:  mock, stub
falso
All the Fake Data for All Your Real Needs 🙂
Stars: ✭ 877 (+777%)
Mutual labels:  mock, fake
Hippolyte
HTTP Stubbing in Swift
Stars: ✭ 109 (+9%)
Mutual labels:  mock, stub
Swiftmockgeneratorforxcode
An Xcode extension (plugin) to generate Swift test doubles automatically.
Stars: ✭ 522 (+422%)
Mutual labels:  mock, stub
phake
PHP Mocking Framework
Stars: ✭ 464 (+364%)
Mutual labels:  mock, stub
Strictly fake
Stub that automatically verifies that stubbed methods exist and the signatures match the original.
Stars: ✭ 18 (-82%)
Mutual labels:  fake, stub
Generator Http Fake Backend
Yeoman generator for building a fake backend by providing the content of JSON files or JavaScript objects through configurable routes.
Stars: ✭ 49 (-51%)
Mutual labels:  fake, mock
Sns
Fake Amazon SNS
Stars: ✭ 94 (-6%)
Mutual labels:  fake, mock
Fake server
FakeServer integrates with ExUnit to make external APIs testing simpler
Stars: ✭ 64 (-36%)
Mutual labels:  fake, stub
Wiremockui
Wiremock UI - Tool for creating mock servers, proxies servers and proxies servers with the option to save the data traffic from an existing API or Site.
Stars: ✭ 38 (-62%)
Mutual labels:  mock, stub

CircleCI

Impersonator

Impersonator is a Ruby library to record and replay object interactions.

When testing, you often find services that are expensive to invoke, and you need to use a double instead. Creating stubs and mocks for simple scenarios is easy, but, for complex interactions, things get messy fast. Stubbing elaborated canned response and orchestrating multiple expectations quickly degenerates in brittle tests that are hard to write and maintain.

Impersonator comes to the rescue. Given an object and a list of methods to impersonate:

  • The first time each method is invoked, it will record its invocations, including passed arguments, return values, and yielded values. This is known as record mode.
  • The next times, it will reproduce the recorded values and will validate that the method was invoked with the same arguments, in a specific order and the exact number of times. This is known as replay mode.

Impersonator only focuses on validating invocation signature and reproducing output values, which is perfect for many services. It won't work for services that trigger additional logic that is relevant to the test (e.g., if the method sends an email, the impersonated method won't send it).

Familiar with VCR? Impersonator is like VCR but for ruby objects instead of HTTP.

Installation

Add this line to your application's Gemfile:

gem 'impersonator', group: :test

And then execute:

$ bundle

Usage

Use Impersonator.impersonate passing in a list of methods to impersonate and a block that will instantiate the object at record time:

calculator = Impersonator.impersonate(:add, :divide) { Calculator.new }
  • At record time, Calculator will be instantiated and their methods normally invoked, recording the returned values (and yielded values if any).
  • At replay time, Calculator won't be instantiated. Instead, a double object will be generated on the fly that will replay the recorded values.
class Calculator
  def add(number_1, number_2)
    number_1 + number_2
  end
end

# The first time it records...
Impersonator.recording('calculator add') do
  calculator = Impersonator.impersonate(:add) { Calculator.new }
  puts calculator.add(2, 3) # 5
end

# The next time it replays
Object.send :remove_const, :Calculator # Calculator does not even have to exist now
Impersonator.recording('calculator add') do
  calculator = Impersonator.impersonate(:add) { Calculator.new }
  puts calculator.add(2, 3) # 5
end

Typically you will use impersonate for testing, so this is how your test will look:

# The second time the test runs, impersonator will replay the
# recorded results
test 'sums the numbers' do
  Impersonator.recording('calculator add') do
    calculator = Impersonator.impersonate(:add){ Calculator.new }
    assert_equal 5, calculator.add(2, 3)
  end
end

Impersonated methods will record and replay:

  • Arguments
  • Return values
  • Yielded values

Impersonate certain methods only

Use Impersonator#impersonate_methods to impersonate certain methods only. At replay time, the impersonated object will delegate to the actual object all the methods except the impersonated ones.

actual_calculator = Calculator.new
impersonator = Impersonator.impersonate(actual_calculator, :add)

In this case, in replay mode, Calculator gets instantiated normally and any method other than #add will be delegated to actual_calculator.

Configuration

Recordings path

Impersonator works by recording method invocations in YAML format. By default, recordings are saved in:

  • spec/recordings if a spec folder is present in the project
  • test/recordings otherwise

You can configure this path with:

Impersonator.configure do |config|
  config.recordings_path = 'my/own/recording/path'
end

Ignore arguments when matching methods

By default, to determine if a method invocation was right, the list of arguments will be matched with ==. You can configure how this work by providing a list of argument indexes to ignore.

impersonator = Impersonator.impersonate(:add){ Test::Calculator.new }
impersonator.configure_method_matching_for(:add) do |config|
  config.ignore_arguments_at 0
end

# Now the first parameter of #add will be ignored.
#
# In record mode:
impersonator.add(1, 2) # 3

# In replay mode
impersonator.add(9999, 2) # will still return 3 and won't fail because the first argument is ignored

Disabling record mode

You can disable impersonator by passing disable: true to Impersonator.recording:

Impersonator.recording('test recording', disabled: true) do
  # ...
end

This will effectively force record mode at all times. This is handy while you are figuring out how interactions with the mocked service go. It will save the recordings, but it will never use them.

Configuring attributes to serialize

Impersonator relies on Ruby standard YAML library for serializing/deserializing data. It works with simple attributes, arrays, hashes and objects which attributes are serializable in a recurring way. This means that you don't have to care when interchanging value objects, which is a common scenario when impersonating RPC-like clients.

However, there are some types, like Proc, anonymous classes, or IO classes like File, that will make the serialization process fail. You can customize which attributes are serialized by overriding init_with and encode_with in the class you want to serialize. You will typically exclude the problematic attributes by including only the compatible ones.

class MyClass
  # ...
  
  def init_with(coder)
    self.name = coder['name']
  end

  def encode_with(coder)
    coder['name'] = name
  end
end

RSpec configuration

Impersonator is test-framework agnostic. If you are using RSpec, you can configure an around hook that will start a recording session automatically for each example that has an impersonator tag:

RSpec.configure do |config|
  config.around(:example, :impersonator) do |example|
    Impersonator.recording(example.full_description) do
      example.run
    end
  end
end

Now you can just tag your tests with impersonator and an implicit recording named after the example will be available automatically, so you don't have to invoke Impersonator.recording anymore.

describe Calculator, :impersonator do
  it 'sums numbers' do
    # there is an implicit recording stored in 'calculator-sums-numbers.yaml'
    impersonator = Impersonator.impersonate(:add){ Calculator.new }
    expect(impersonator.add(1, 2)).to eq(3)
  end
end

Thanks

  • This library was heavily inspired by VCR. A gem that blew my mind years ago and that has been in my toolbox since then.

Links

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/jorgemanrubia/impersonator.

License

The gem is available as open source under the terms of the MIT License.`

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].