Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added MiniTest test DSL.

  • Loading branch information...
commit 5cab52ea7a6f8370c509b77dfbc85d9861b2247d 1 parent 5148ed0
@hsume2 hsume2 authored
View
3  Gemfile
@@ -12,6 +12,9 @@ group :development do
gem 'mocha'
gem 'bourne'
gem 'pre-commit'
+ gem 'minitest', '2.6.1'
+ gem 'minitest-reporters', :require => 'minitest/reporters'
+ gem 'guard-shell'
end
gem 'builder'
View
12 Gemfile.lock
@@ -5,6 +5,7 @@ GEM
activesupport (= 2.3.12)
rack (~> 1.1.0)
activesupport (2.3.12)
+ ansi (1.3.0)
bourne (1.0)
mocha (= 0.9.8)
builder (3.0.0)
@@ -13,6 +14,8 @@ GEM
git (1.2.5)
guard (0.7.0)
thor (~> 0.14.6)
+ guard-shell (0.1.1)
+ guard (>= 0.2.0)
guard-test (0.3.0)
guard (>= 0.2.2)
test-unit (~> 2.2)
@@ -21,6 +24,11 @@ GEM
bundler (~> 1.0)
git (>= 1.2.5)
rake
+ minitest (2.6.1)
+ minitest-reporters (0.4.0)
+ ansi
+ minitest (~> 2.0)
+ ruby-progressbar
mocha (0.9.8)
rake
multi_json (1.0.3)
@@ -29,6 +37,7 @@ GEM
rack (1.1.2)
rake (0.9.2)
rcov (0.9.9)
+ ruby-progressbar (0.0.10)
shoulda (2.11.3)
test-unit (2.3.0)
thor (0.14.6)
@@ -42,9 +51,12 @@ DEPENDENCIES
builder
bundler (~> 1.0.0)
guard
+ guard-shell
guard-test
hsume2-state_machine (~> 1.0.5)
jeweler (~> 1.6.4)
+ minitest (= 2.6.1)
+ minitest-reporters
mocha
pre-commit
rcov
View
9 Guardfile.minitest
@@ -0,0 +1,9 @@
+def run_tests
+ system("ruby minitest/run.rb")
+end
+
+guard 'shell' do
+ watch(%r{^lib/(.+)\.rb$}) { run_tests }
+ watch(%r{^minitest/.+_test\.rb$}) { run_tests }
+ watch('minitest/helper.rb') { run_tests }
+end
View
16 call_center.gemspec
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Henry Hsu"]
- s.date = %q{2011-10-23}
+ s.date = %q{2011-10-24}
s.description = %q{Support for describing call center workflows}
s.email = %q{hhsu@zendesk.com}
s.extra_rdoc_files = [
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
"Gemfile",
"Gemfile.lock",
"Guardfile",
+ "Guardfile.minitest",
"LICENSE.txt",
"README.md",
"Rakefile",
@@ -33,6 +34,10 @@ Gem::Specification.new do |s|
"lib/call_center/flow_callback.rb",
"lib/call_center/state_machine_ext.rb",
"lib/call_center/test/dsl.rb",
+ "lib/call_center/test/minitest/dsl.rb",
+ "minitest/call_center/test/minitest_test.rb",
+ "minitest/helper.rb",
+ "minitest/run.rb",
"test/call_center_test.rb",
"test/core_ext_test.rb",
"test/examples/call.rb",
@@ -64,6 +69,9 @@ Gem::Specification.new do |s|
s.add_development_dependency(%q<mocha>, [">= 0"])
s.add_development_dependency(%q<bourne>, [">= 0"])
s.add_development_dependency(%q<pre-commit>, [">= 0"])
+ s.add_development_dependency(%q<minitest>, ["= 2.6.1"])
+ s.add_development_dependency(%q<minitest-reporters>, [">= 0"])
+ s.add_development_dependency(%q<guard-shell>, [">= 0"])
else
s.add_dependency(%q<builder>, [">= 0"])
s.add_dependency(%q<hsume2-state_machine>, ["~> 1.0.5"])
@@ -78,6 +86,9 @@ Gem::Specification.new do |s|
s.add_dependency(%q<mocha>, [">= 0"])
s.add_dependency(%q<bourne>, [">= 0"])
s.add_dependency(%q<pre-commit>, [">= 0"])
+ s.add_dependency(%q<minitest>, ["= 2.6.1"])
+ s.add_dependency(%q<minitest-reporters>, [">= 0"])
+ s.add_dependency(%q<guard-shell>, [">= 0"])
end
else
s.add_dependency(%q<builder>, [">= 0"])
@@ -93,6 +104,9 @@ Gem::Specification.new do |s|
s.add_dependency(%q<mocha>, [">= 0"])
s.add_dependency(%q<bourne>, [">= 0"])
s.add_dependency(%q<pre-commit>, [">= 0"])
+ s.add_dependency(%q<minitest>, ["= 2.6.1"])
+ s.add_dependency(%q<minitest-reporters>, [">= 0"])
+ s.add_dependency(%q<guard-shell>, [">= 0"])
end
end
View
224 lib/call_center/test/minitest/dsl.rb
@@ -0,0 +1,224 @@
+require 'action_controller/vendor/html-scanner'
+require 'action_controller/assertions/selector_assertions'
+require 'test/unit/assertions'
+
+module CallCenter
+ module Test
+ module MiniTest
+ module DSL
+ class ItShouldFlow
+ def initialize(context, &block)
+ @context = context
+ self.instance_eval(&block)
+ verify
+ end
+
+ def on(event)
+ @event = event
+ self
+ end
+
+ def from(from_state)
+ @from = from_state.to_s
+ self
+ end
+
+ def to(to_state)
+ @to = to_state.to_s
+ self
+ end
+
+ class Expectation
+ attr_reader :name
+
+ def initialize(name)
+ @name = name
+ end
+
+ def setup(object)
+ raise 'Implement in subclass'
+ end
+ end
+
+ class Expects < Expectation
+ def initialize(name, &blk)
+ super(name)
+ @expectation_block = blk
+ end
+
+ def setup(object)
+ mocka = object.expects(name)
+ @expectation_block.call(mocka) if @expectation_block
+ end
+ end
+
+ class Stubs < Expects
+ def setup(object)
+ mocka = object.stubs(name)
+ @expectation_block.call(mocka) if @expectation_block
+ end
+ end
+
+ class Condition < Expectation
+
+ end
+
+ class IfCondition < Expectation
+ def setup(object)
+ object.stubs(name).returns(true)
+ end
+ end
+
+ class UnlessCondition < Expectation
+ def setup(object)
+ object.stubs(name).returns(false)
+ end
+ end
+
+ def expects(method_name, &blk)
+ @expectations ||= []
+ @expectations << Expects.new(method_name, &blk)
+ self
+ end
+
+ def stubs(method_name, &blk)
+ @expectations ||= []
+ @expectations << Stubs.new(method_name, &blk)
+ self
+ end
+
+ def if(condition)
+ @expectations ||= []
+ @expectations << IfCondition.new(condition)
+ self
+ end
+
+ def unless(condition)
+ @expectations ||= []
+ @expectations << UnlessCondition.new(condition)
+ self
+ end
+
+ def restubs(object, *without)
+ without = [without].flatten
+ s_m = object.class.current_state_machine
+ stub_methods = (after_transition_methods(s_m) | if_and_unless_conditions(s_m)).uniq - without
+ object.reset_mocha
+ stub_methods.each do |m|
+ object.stubs(m)
+ end
+ end
+
+ def after_transition_methods(s_m)
+ s_m.callbacks.values.flatten.map { |c| c.instance_variable_get(:@methods) }.flatten.select { |m| m.is_a?(Symbol) }
+ end
+
+ def if_and_unless_conditions(s_m)
+ branches = s_m.events.map(&:branches).flatten
+ branches.map(&:if_condition).compact | branches.map(&:unless_condition).compact
+ end
+
+ def verify
+ event, from, to = @event, @from, @to
+ expectations = @expectations || []
+ helper = self
+ @context.it(description) do
+ helper.restubs(subject, expectations.map(&:name))
+ expectations.each do |expectation|
+ expectation.setup(subject)
+ end
+ state_field = defined?(call_center_state_field) ? call_center_state_field.to_sym : :state
+ subject.send(:"#{state_field}=", from)
+ subject.send(:"#{event}!")
+ subject.send(state_field).must_equal(to)
+ end
+ end
+
+ private
+
+ def description
+ "should flow on ##{@event}! from :#{@from} to :#{@to}"
+ end
+ end
+
+ class ItShouldRender < ItShouldFlow
+ def is(state)
+ @state = state
+ self
+ end
+
+ class Assertion
+ def initialize(*args)
+ @args = args
+ end
+
+ def setup(context)
+ context.assert_select(*@args)
+ end
+ end
+
+ def selects(selector, matcher = nil)
+ @assertions ||= []
+ @assertions << Assertion.new(selector, matcher)
+ self
+ end
+
+ def verify
+ state = @state
+ expectations = @expectations || []
+ assertions = @assertions || []
+ helper = self
+ @context.it(description) do
+ helper.restubs(subject, expectations.map(&:name))
+ expectations.each do |expectation|
+ expectation.setup(subject)
+ end
+ state_field = defined?(call_center_state_field) ? call_center_state_field.to_sym : :state
+ subject.send(:"#{state_field}=", state)
+ body(subject.render)
+ assertions.each do |assertion|
+ assertion.setup(self)
+ end
+ end
+ end
+
+ private
+
+ def description
+ "should render when :#{@state}"
+ end
+ end
+
+ if defined?(::MiniTest::Spec)
+ ::MiniTest::Spec.class_eval do
+ include ActionController::Assertions::SelectorAssertions
+
+ def self.it_should_flow(&block)
+ CallCenter::Test::MiniTest::DSL::ItShouldFlow.new(self, &block)
+ end
+
+ def self.it_should_render(&block)
+ CallCenter::Test::MiniTest::DSL::ItShouldRender.new(self, &block)
+ end
+
+ def response_from_page_or_rjs
+ HTML::Document.new(@_body).root
+ end
+
+ def body(text, debug = false)
+ puts text if debug
+ @_body = text
+ end
+
+ private
+
+ def build_message(head, template=nil, *arguments)
+ template &&= template.chomp
+ return ::Test::Unit::Assertions::AssertionMessage.new(head, template, arguments)
+ end
+ end
+ end
+ end
+ end
+ end
+end
View
20 minitest/call_center/test/minitest_test.rb
@@ -0,0 +1,20 @@
+require 'minitest/helper'
+require 'call_center/test/minitest/dsl'
+
+require 'test/examples/call'
+
+describe CallCenter::Test::MiniTest::DSL do
+ subject { Call.new }
+ let(:call_center_state_field) { :state }
+
+ it_should_flow { on(:incoming_call).from(:initial).to(:routing).if(:agents_available?) }
+ it_should_flow { on(:incoming_call).from(:initial).to(:voicemail).unless(:agents_available?) }
+ it_should_render { is(:initial).expects(:notify).selects("Response>Say", "Hello World") }
+
+ it_should_flow { on(:customer_hangs_up).from(:voicemail).to(:voicemail_completed) }
+ it_should_render { is(:voicemail).expects(:notify).selects("Response>Say", "Hello World").selects("Response>Record[action=/voice/calls/flow?event=voicemail_complete&amp;actor=customer]") }
+
+ it_should_flow { on(:something_crazy_happens).from(:initial).to(:uh_oh) }
+
+ it_should_flow { on(:customer_hangs_up).from(:cancelled).to(:cancelled).expects(:cancelled) { |e| e.never } }
+end
View
23 minitest/helper.rb
@@ -0,0 +1,23 @@
+require 'rubygems'
+require 'bundler'
+begin
+ Bundler.setup(:default, :development)
+rescue Bundler::BundlerError => e
+ $stderr.puts e.message
+ $stderr.puts "Run `bundle install` to install missing gems"
+ exit e.status_code
+end
+require 'minitest/autorun'
+require 'mocha'
+require 'active_support'
+
+$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+require 'call_center'
+
+module CommonCallMethods
+ def agents_available?; end
+ def voicemail; end
+ def voicemail_completed; end
+ def routing; end
+end
View
15 minitest/run.rb
@@ -0,0 +1,15 @@
+project_root = File.expand_path('..', File.dirname(__FILE__))
+lib_dir = File.join(project_root, 'lib')
+test_dir = File.join(project_root, 'minitest')
+
+begin
+ require 'minitest/reporters'
+ MiniTest::Unit.runner = MiniTest::SuiteRunner.new
+ MiniTest::Unit.runner.reporters << MiniTest::Reporters::ProgressReporter.new
+rescue LoadError
+ puts "MiniTest::Reporters not available."
+end
+
+puts "\n\n"
+test_files = File.join(test_dir, '**/*_test.rb')
+Dir[test_files].each { |file| require file }
Please sign in to comment.
Something went wrong with that request. Please try again.