Bogus is a RubyAPI library used for minimizing risks involved in isolated unit testing. It was initially released in July 2012 by rubygems.org. Through Bogus, a piece of code can be tested in a fast and safe manner, without any actual integration with external programs. Bogus cannot mock or stub methods not present in the required external environment.
Features
Ruby provides various features to achieve the required testing framework.
Fakes
Fakes are lightweight objects that mock actual objects' interface. In order to test a class in isolation, usually some test doubles or anonymous objects are used in place of integrated classes with required methods stubbed in it. But there is a problem with this approach, If the class is changed in between, those changes are not reflected in mock objects and tests run without any integration exceptions. Fakes resolve this problem as they will have exact interface of real collaborator and will raise an exception whenever the actual class is modified. Fakes can be implemented using the following methodologies.
Faking existing classes
A fake is created by calling fake method: Syntax: fake "fake_name" is the name of the created fake and can be used to identify the fake while using contract tests. if it is omitted then an anonymous fake is created. A fake provides options to return an instance or a copy of class depending on the requirement. Fakes can be applied to stub methods as well.
Global configuration
Fakes avoid the need of stubbing and eliminate much of configuration things like. Regardless, this type of configuration should be added to fake definitions, and the more collaborators one has, there will be more duplication. Bogus deals with this problem by introducing DSL to configure fakes in a single place, thus unifying its use in all the tests. Stubbed methods can be overridden using fake macros or fake helper functions.
Nameless test doubles
Anonymous test doubles can be used as intermediate steps while migrating objects from another testing library. They help in observing methods without mocking them. Methods can be stubbed:
with any number of arguments
in an initialize method
inline
to invoke arbitrary methods
Replacing classes
Usually dependency injections are used to make the composition of classes easy and make the code more modular. Replacement of classes with fakes avoids this requirement. Different fake names can be given to created fake classes.
A system may have multiple classes implementing a single function. This complicates the selection of an implementation for that particular scenario. Bogus solves this problem by creating a duck type for classes. Syntax to create a duck type: make_duck Bogus simplifies it further by creating duck types automatically when more than one class are returned from fake. Indeed, it does it in global configuration as well.
Contract tests
In order to verify that exception handling is done as expected in the fake stub, a sample test should be written for the mock object. This test is not written by Bogus, but it reminds the developer to do so. verify_contract method records all the interceptions made with the real class, and fails the test if any scenario recorded on an fake object that has been forgotten to be tested. Whenever an object is mocked, stubbed or spied, a contract is specified on input/output parameters. Bogus automatically verifies whether the contract is satisfied or not. They fail when mocked or stubbed methods are not called on real objects. Contract tests not only check whether correct number of parameters are passed but also makes sure that the object is tested with right arguments. Contract verification can be identified correctly only when passed block of code or arguments are idempotent and without any side effects.
Stubbing
In addition to fakes, bogus allows stubs in the cases where the inversion of control principle is not used. They follow two conditions:
The passing parameters need to be consistent. It retains the method signature.
The syntax is similar to that of ruby stubbing:
RR syntax
stub.method_name
Bogus syntax
stub.method_name The main difference between fakes and stubbing is that in fakes, method call can be verified before stubbing. But in stubbing, to verify that a method call has occurred, stubbing beforehand is necessary.
Safe mocking
Mocks are used to test an object in isolation. These help to find out if there is proper communication between the object and its collaborators. Mocks are like stubs in the way that the object and the method being mocked need to exist. Syntax: mock.method_name
Spies
When the code is being tested, the message transmission and reception is a vital part. This is verified using spies. They are used to specify what needs to happen in the ideal case. Spies verify that a method is called before stubbing it.
Argument matchers
Argument matchers are helpful when the details of the passing arguments are not as important as knowing if the method is being called or not. Instead of the actual arguments, some matchers like wildcard entries or regular expressions can be used.
Configuration options
Bogus configuration syntax: Bogus.configure do |c| c.search_modules = c.fake_ar_attributes = true end
Search_modules
By default, Bogus does not maintain a namespace. Therefore, during the search for a particular class, the search is performed on all of the identifiers. In order to narrow down the search space, Search_modules can be customized to include a particular module of classes. For example: Bogus.configure do |c| c.search_modules << Bar end Here, 'Bar' is a module which contains a set of classes where the search has to be performed.
Fake_ar_modules
This feature deals with the ActiveRecord::Base class. Here, the Active Record is a module and Base is one of its classes. Active Record's attributes are not explicit. Their modification is done in the database directly. The Base class is a special class that has methods it responds to but doesn't explicitly mention as its own methods. Therefore, when such a method is faked, it raises an error because the method does not exist for the class. For example, class BlogPost < ActiveRecord::Base end blog_post = BlogPost.new blog_post.respond_to? # => true blog_post.method # raises NameError To avoid this problem, fake_ar_modules is set to true. Then fakes can be created with no error.
RSpec Mocks vs Bogus
Bogus isolates objects while unit testing i.e., it does not require any information of classes or objects involved in testing object method, whereas Rspec Mocks require additional information regarding objects used in testing object. One major advantage of using bogus over Rspec Mocks is that Bogus provides safe stubbing.