class ASpec

ASpec is a simple library that utilizes aspect oriented programming and meta programming to enable stubing, method call counting, Liskov Substition Principle testing and more

Attributes

expected_method_call_arguments[R]
expected_method_call_counts[R]
method_call_arguments[R]
method_call_counts[R]
return_values[R]

Public Class Methods

class_substition(original_class) click to toggle source

Get the name of the class that should be replacing the original class in LSP testing

# File lib/aspeclib.rb, line 27
def self.class_substition(original_class)
  return @@class_substitutions[original_class]
end
define_new_method(replaced_class) click to toggle source

Replaces the constructor of the given class with the one from the LSP class subsititutions list

# File lib/aspeclib.rb, line 102
def self.define_new_method(replaced_class)
  def (eval(replaced_class)).new
    obj = nil
    if ASpec.class_substition(self.to_s).nil?
      the_ancestor = ''
      self.ancestors.each do |ancestor|
        unless ASpec.class_substition(ancestor.to_s).nil?
          the_ancestor = ancestor.to_s
          break
        end
      end
      ASpec.remove_new_method_from_class(the_ancestor)
      obj = self.new
      ASpec.define_new_method(the_ancestor)
    else
      ASpec.remove_new_method_from_class(self.to_s)
      obj = eval(ASpec.class_substition(self.to_s)).new
      ASpec.define_new_method(self.to_s)
    end
    obj
  end
end
new() click to toggle source
# File lib/aspeclib.rb, line 14
def initialize
  @replaced_class = ''
  @replacing_classes = [nil]
  @method_stubs = {}
  @aspects = []
  @return_values = []
  @method_call_counts = {}
  @expected_method_call_counts = {}
  @method_call_arguments = {}
  @expected_method_call_arguments = {}
end
remove_new_method_from_class(class_name) click to toggle source

Removes the arbitrary new constructor from the given class

# File lib/aspeclib.rb, line 126
def self.remove_new_method_from_class(class_name)
  class <<(eval(class_name))
    remove_method :new
  end
end

Public Instance Methods

count_method_calls(type, method, expected_count) click to toggle source

Defines the expected count of method calls for the method in the type

# File lib/aspeclib.rb, line 73
def count_method_calls(type, method, expected_count)
  type, method, expected_count = type.to_s, method.to_s, expected_count.to_i
  (@expected_method_call_counts[type] ||= {})[method] = expected_count
  (@method_call_counts[type] ||= {})[method] = 0

  aspect = Aspect.new :around, :calls_to => method, :for_type => eval(type) do |join_point, object, *args|
    @method_call_counts[object.class.to_s][join_point.method_name.to_s] += 1
  end

  @aspects << aspect
  self
end
execute() { || ... } click to toggle source

Executes the given block If there are LSP substitutes defined, executes the block for each of them

# File lib/aspeclib.rb, line 134
def execute
  @replacing_classes.each do |replacing_class|

    unless replacing_class.nil?
      @@class_substitutions[@replaced_class] = replacing_class
      ASpec.define_new_method(@replaced_class)
    end

    @return_values << yield

    ASpec.remove_new_method_from_class(@replaced_class) unless replacing_class.nil?
  end

  @aspects.each do |aspect|
    aspect.unadvise
  end
  @aspects.clear

  self
end
expect_method_arguments(type, method, expected_arguments) click to toggle source

Defines the expected method arguments for each of the method calls expected_arguments is a list of lists of arguments, e.g. [[call1_arg1, call1_arg2], [call2_arg1, call2_arg2]]

# File lib/aspeclib.rb, line 88
def expect_method_arguments(type, method, expected_arguments)
  type, method = type.to_s, method.to_s
  (@expected_method_call_arguments[type] ||= {})[method] = expected_arguments
  (@method_call_arguments[type] ||= {})[method] = []

  aspect = Aspect.new :around, :calls_to => method, :for_type => eval(type) do |join_point, object, *args|
    (@method_call_arguments[object.class.to_s][join_point.method_name.to_s] ||= []) << args
  end

  @aspects << aspect
  self
end
lsp(replaced_class, replacing_classes) click to toggle source

Test Liskov Substition Principle Replaces the replaced_class with each of the replacing_classes during execution

# File lib/aspeclib.rb, line 33
def lsp(replaced_class, replacing_classes)
  @replaced_class = replaced_class.to_s
  @replacing_classes += if replacing_classes.class == Array
    replacing_classes.map {|item| item.to_s}
  else
    [replacing_classes.to_s]
  end
  self
end
raise_exception(type, method) click to toggle source

Raises exception when the method of the type is called

# File lib/aspeclib.rb, line 62
def raise_exception(type, method)
  type, method = type.to_s, method.to_s
  aspect = Aspect.new :around, :calls_to => method, :for_type => eval(type) do |join_point, object, *args|
    raise "ASpec doesn't like this at all."
  end

  @aspects << aspect
  self
end
return_value() click to toggle source

The first returned value from the execution

# File lib/aspeclib.rb, line 156
def return_value
  @return_values.first
end
stub(type, method, &block) click to toggle source

Replaces the method of the type with the given block

# File lib/aspeclib.rb, line 44
def stub(type, method, &block)
  type, method = type.to_s, method.to_s
  @method_stubs[[type, method]] = block

  aspect = Aspect.new :around, :calls_to => method, :for_type => eval(type) do |join_point, object, *args|
    key = [object.class.to_s, join_point.method_name.to_s]
    if @method_stubs.has_key? key
      @method_stubs[key].call
    else
      jp.proceed
    end
  end

  @aspects << aspect
  self
end