Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

aidmock

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

aidmock

  • 0.4.0
  • Rubygems
  • Socket score

Version published
Maintainers
1
Created
Source

h1. Aidmock

Aidmock is an safe mock and interfacing library for Ruby.

Aidmock doesn't target any specific mock or test framework. Our goal is to provide a wide solution, that supports the major mock and test frameworks. For now we are only supporting RSpec 2 and RSpec Mocks, but more drivers for other frameworks will be available soon.

The basic idea of Aidmock is we believe that Mocks are good, but they can be scary too, leading to false positives. Aidmock tries to make it safer. To read more about motivation, see the "motivation":https://github.com/wilkerlucio/aidmock/wiki/Motivation page.

Aidmock also generate some sanity checks for your interfaces, so defining interfaces can be a nice point when starting the defition of your classes. Let's start with setup and configuration, then we will see how to define our interfaces.

h2. Installation

To install Aidmock just run:

bc. gem install aidmock

Or add it to your Gemfile:

bc. gem "aidmock"

h2. Configuration

In order to use Aidmock, you need to configure it on your test environment. Since it's only working on RSpec for now you need to configure your @spec_helper@:

bc.. RSpec.configure do |config| config.before :all do Aidmock.setup! # it will do any nescessary setup, like extending your framework mocks end

config.after :each do Aidmock.verify! # it will verify created mocks after each spec end end

load or write your interfaces here

Aidmock::Sanity.sanitize! # it will run sanity checks, just call it after have all interfaces defined

h2. Automatic Interfacing

Since version 0.3.1 Aidmock supports automatic interfacing, this feature is enabled by default. With automatic interfacing Aidmock will define the class interface automatically for you if the interface is not already defined, we still encorage you to do some manual interface definitions since automatic interfacing can't be too much precise (it will generate method names and correct arity, but can't check value real types). But automatic interfaces is a nice start point for you at Aidmock, no need for big setups, work with third-part code (also built-in Ruby code too) and will give to you a new layer of safe to your mocks.

Even when you start doing interfaces by hand, you may want to still having this feature enabled, since it will interface third-part code and built-in code.

If you wanna do a hardcore Aidmock use, you can disable automatic interfacing with following snippet:

bc. Aidmock.autointerface = false

h2. How It Works

Aidmock runs after each test you do. It will get the mocks/stubs defined by your test and match these doubles with the interface you have defined for that object. If your mock doesn't respect your interface, it will raise an error, preventing you from having a false positive. Simple :)

h3. Remember to constrain your mocks

Sometimes you wanna do something like this:

bc. obj = mock obj.should_receive(:something)

With Aidmock we can't detect the class with only this, so, for a safe mocking on this cases you should constrain the mock for one class or module that you already interfaced:

bc. obj = mock.constrained_to(SomeInterface) obj.should_receive(:something)

This way can clear parse it.

h3. No interface warn

By default, Aidmock will warn you when you try to mock/stub something that you haven't interfaced. You can remove this warn with following snippet:

bc. Aidmock.warn_undefined_interface = false

h2. Interfacing

The major point of Aidmock is interfacing: it's when you define how your object's are supposed to work. It's really like you define methods on static languages as C or Java, but it's more dynamic and cool to work with. :)

Let's try it and define a simple interface:

bc.. Aidmock.interface Person do method :first_name, String method :first_name=, nil, String

method :last_name, String method :last_name=, nil, String

method :full_name, String end

p. Ok, let's take some time to look at what we are doing. We use a DSL created by Aidmock to define the class interface. In this case we use @method@ to describe an instance method. The first argument is the method name, the second one is the return, and after return we can send any number of params we want: they are the arguments.

The return and arguments in fact are matchers; they match if the value used corresponds to the matcher. In the example above, we used two different kind of matchers: the @KindOfMatcher@ (when we used the String class, it created this matcher) and the @AnythingMatcher@ (when we used nil).

This interface will automatically create some specs that check if these methods are defined on @Person@ class and if they respect the method arity. And most important, when you stub or mock the Person, it will check the interface and if you are mocking with correct params and return values; this will make your double safe.

h3. Class Methods

For interfacing class methods just use @class_method@ instead of @method@. Everything else is same for both.

h3. Method Names

The method names can be specified as symbol or regexp. Use symbol for method exact names and regexp for dynamic names.

bc. Aidmock.Interface MyAR do method :table, Symbol method /find_by_.+/, String end

h2. Matchers

In section above we saw a simple example of how to create an interface. Now we will go deeper and see all the available matchers and how to use them.

h3(#conversions). Matcher Conversion

In most of cases, instead of creating a matcher directly, you will use a "Matcher Conversion". It takes simple values and create matchers based on them. In the table above you can see all available conversions:

|. Object Type |. Matcher |_. Description | | Class | KindOfMatcher | if object is class, it will create a @KindOfMatcher@ with the given class | | Array | AnyMatcher | if the object is an array, it will create an @AnyMatcher@, where each item of array will be an matcher | | nil | AnythingMatcher | if the object is nil, it will create an @AnythingMatcher@ | | Symbol | DuckTypeMatcher | if the object is a symbol, it will create an @DuckTypeMatcher@ that responds to it | | Hash | HashMatcher | if the object is an hash, it will create an @HashMatcher@ with given hash |

h3(#any_matcher). AnyMatcher

This matcher can be used when you want to have more than one matcher option. It takes a list of matchers (or use a value to be converted by "conversions":#conversions) and it will match if any of these matchers matches.

DSL helper: @any_of(*matchers)@ Conversion: use an array

Example:

bc. method :concat, String, [String, Fixnum] method :concat, String, any_of(String, Fixnum) # same as line above

h3(#anything_matcher). AnythingMatcher

This matcher will simply accept anything.

DSL Helper: @anything@ Conversion: use a @nil@

Example:

bc. method :puts, nil method :puts, anything #same as line above

h3(#duck_type_matcher). DuckTypeMatcher

Duck type matcher will check if an object responds to all the given methods.

DSL Helper: @respond_to(*methods)@ Conversion: use a symbol

Example:

bc. method :write, :to_s method :write, respond_to(:to_s) # same as line above

h3(#instance_of_matcher). InstanceOfMatcher

Check if the object is the instance of given class.

DSL Helper: @instance_of(klass)@

Example:

bc. method :to_s, instance_of(String)

h3(#kind_of_matcher). KindOfMatcher

Check the object is the kind of given class.

DSL Helper: @kind_of(klass)@ Conversion: use any class

Example:

bc. method :find, ActiveRecord::Base method :find, kind_of(ActiveRecord::Base) # same as above line

h3(#hash_matcher). HashMatcher

The hash matcher checks if the argument is a hash and each key defined on it. If the user sends a hash with a key that is not present on the hash definition, it will fail. It also checks the value type of each key. By default it will ignore if the user doesn't send all expected options (which is a common pattern for options arguments), but it has a strict mode that will require all the keys to be defined.

DSL Helper: @hash_including(hash, strict = false)@ Conversion: use any hash

Example:

bc. method :find, {:conditions => [String, Array], :order => String} method :find, has_including(:conditions => [String, Array], :order => String) # same as above method :find, has_including({:conditions => [String, Array], :order => String}, true) # will require to be called with all keys defined

h3(#not_nil_arg_matcher). NotNilArgMatcher

By default, all matchers will accept a @nil@ value. If you want to require the value (making a @nil@ return false), you can use this matcher. You also need to send a matcher as param (to check when value is not nil, you can use the conversions too).

DSL Helper: @not_nil(matcher)@ or @nn(matcher)@

Example:

bc. method :name=, nil, nn(String) method :name=, nil, not_nil(String) # same as above

h3(#optional_arg_matcher). OptionalArgMatcher

When you want optional arguments, the @OptionalArgMatcher@ will solve it for you. This matcher is only valid for arguments.

DSL Helper: @optional(matcher)@ or @o(matcher)@

Example:

bc. method :something, nil, o(String) method :something, nil, optional(String) # same as above

h3(#splat_arg_matcher). SplatArgMatcher

When you want to use splat arguments (example: @def thing(*args)@) this matcher will interface it, you also need to send an matcher (or conversion) to it, and each value of splat will be matched by this matcher. This matcher is only valid for arguments.

DSL Helper: @splat(matcher)@ or @s(matcher)@

Example:

bc. method :something, s(nil) # will accept splat with anything(nil will be converted one AnythingMatcher) method :something, splat(nil) # same as above

h2. Mixing automatic and manual interfaces

Why just manual OR automatic interfacing? You can have both! You can tell Aidmock to fill the interface with automatic generated methods, and them just override with manual interface, to do this, just send @:auto => true@ to interface definition:

bc.. Aidmock.interface Person, :auto => true do method :name, String end

h2. Class Inheritance and Modules

Aidmock respects your class inheritance and module definition, so, the below example will be valid:

bc.. class Animal def scream(noise) puts noise.to_s + "!!!" end end

class Dog < Animal end

Aidmock.interface Animal do method :scream, String, :to_s end

it "test inheritance" do dog = mock.constrained_to(Dog) dog.stub(:scream).with("ha").and_return("ha!!!") # this stub will be verified as you expect end

h2. Changelog

h3. 0.4.0

  • Fixed automatic generation step
  • Hability to mix automatic interfacing with manual interface
  • Methods: Aidmock.setup, Aidmock.verify, Aidmock::Sanity.sanitize now requires ! (now you should use Aidmock.setup!, Aidmock.verify!, Aidmock::Sanity.sanitize!)

h3. 0.3.1

  • Supporting automatic interfacing

h3. 0.3.0

  • bad release, ignore this version please

h3. 0.2.0

  • Added .constrained_to to mocks

h3. 0.1.0

  • initial version

h2. Feedback

Aidmock still be somekind of experimental project, any feedback will help a lot. Please use github issues for reporting any bug and/or suggestion :)

FAQs

Package last updated on 07 Feb 2011

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc