Permalink
Browse files

make contexts shareable from testcase

  • Loading branch information...
1 parent 88076da commit cb0918f9bf445cc833207a0d421ab1bf4cf18e7f Sven Fuchs committed Dec 1, 2008
Showing with 145 additions and 125 deletions.
  1. +15 −6 lib/with.rb
  2. +12 −10 lib/with/context.rb
  3. +23 −11 lib/with/dsl.rb
  4. +8 −10 lib/with/group.rb
  5. +28 −29 test/demo.rb
  6. +13 −13 test/testunit_with_test.rb
  7. +46 −46 test/with_test.rb
View
@@ -4,12 +4,21 @@
module With
def self.included(base)
- base.send :include, Dsl::Sharing
+ base.send :extend, ClassMethods
end
-
- def describe(name, &block)
- group = Group.new name, &block
- group.compile(self)
- group
+
+ module ClassMethods
+ include Dsl::Sharing
+
+ def inherited(base)
+ base.instance_variable_set(:@shared, @shared)
+ end
+
+ def describe(name, &block)
+ group = Group.new name, &block
+ shared.each {|name, blocks| group.share(name, *blocks) }
+ group.compile(self)
+ group
+ end
end
end
View
@@ -9,43 +9,45 @@ class Context
def initialize(name, action, preconditions, assertions, &block)
@name, @action, @preconditions, @assertions = name, action, [], []
@children = []
+
instance_eval &block if block
+
@preconditions += preconditions
@assertions += assertions
end
-
+
def leafs
return self if children.empty?
children.map { |child| child.leafs }.flatten
end
-
+
def calls
[find_action, collect_preconditions, collect_assertions]
end
-
+
def add_children(*children)
children.each do |child|
child.parent = self
@children << child
end
end
-
+
def self_and_parents
(parent ? parent.self_and_parents : []) + [self]
end
-
+
protected
-
+
def find_action
@action || parent && parent.find_action || raise("could not find action")
end
-
+
def collect_preconditions
- (parent ? parent.collect_preconditions : []) + @preconditions
+ (parent ? parent.collect_preconditions : []) + preconditions
end
-
+
def collect_assertions
- (parent ? parent.collect_assertions : []) + @assertions
+ (parent ? parent.collect_assertions : []) + assertions
end
end
end
View
@@ -3,39 +3,51 @@ module Dsl
def self.included(base)
base.send :include, Sharing
end
-
- attr_reader :children
+
attr_accessor :parent
- attr_reader :preconditions
- attr_reader :assertions
-
def with(*names, &block)
names << { :parent => self }
Group.new(*names, &block)
end
-
+
def before(name = nil, &block)
name ||= "before #{block.inspect}"
- @preconditions << NamedBlock.new(name, &block)
+ preconditions << NamedBlock.new(name, &block)
end
-
+
def action(name = nil, &block)
name ||= "action #{block.inspect}"
@action = NamedBlock.new(name, &block)
end
-
+
def assertion(name = nil, options = {}, &block)
group = options[:with] ? with(*options[:with]) : self
group.assertions << NamedBlock.new(name, &block)
end
alias :it :assertion
-
+
+ def children
+ @children ||= []
+ end
+
+ def preconditions
+ @preconditions ||= []
+ end
+
+ def assertions
+ @assertions ||= []
+ end
+
module Sharing
def share(*blocks, &block)
name = blocks.shift
blocks << block if block
- @shared[name] = blocks
+ shared[name] = blocks
+ end
+
+ def shared
+ @shared ||= {}
end
end
end
View
@@ -10,19 +10,17 @@ def initialize(*args, &block)
options = args.last.is_a?(Hash) ? args.pop : {}
@parent = options[:parent]
@parent.children << self if @parent
-
@names = args
- @children, @assertions, @preconditions, @shared = [], [], [], {}
instance_eval &block if block
end
-
+
def compile(target)
expand.first.leafs.each { |leaf| define_test_method(target, leaf) }
end
-
+
protected
-
+
def expand
names.map do |name|
shared_blocks = find_shared(name) || [nil]
@@ -33,22 +31,22 @@ def expand
end
end.flatten
end
-
+
def find_shared(name)
- @shared[name] || parent && parent.find_shared(name)
+ shared[name] || parent && parent.find_shared(name)
end
-
+
def define_test_method(target, context)
action, preconditions, assertions = *context.calls
method_name = generate_test_method_name(context)
-
+
target.send :define_method, method_name, &lambda {
preconditions.map { |precondition| instance_eval &precondition }
instance_eval &action
assertions.map { |assertion| instance_eval &assertion }
}
end
-
+
def generate_test_method_name(context)
contexts = context.self_and_parents
name = "test_<#{context.object_id}>_#{contexts.shift.name}_"
View
@@ -10,11 +10,11 @@
class Article
attr_reader :errors
-
+
def initialize(attributes)
@attributes = attributes
end
-
+
def save
@errors = ['title', 'body'] - @attributes.keys
@errors.empty?
@@ -25,7 +25,7 @@ class User
def initialize(admin = false)
@admin = admin
end
-
+
def admin?
@admin
end
@@ -34,7 +34,7 @@ def admin?
class ArticlesController < ActionController::Base
attr_accessor :current_user
before_filter :require_admin
-
+
def create
@article = Article.new params
if @article.save
@@ -46,7 +46,7 @@ def create
end
protected
-
+
def require_admin
redirect_to '/login' unless current_user && current_user.admin?
end
@@ -56,19 +56,34 @@ def require_admin
set = ActionController::Routing::RouteSet.new
set.draw {|map| map.articles 'articles', :controller => 'articles', :action => 'create'}
remove_const :Routes
- const_set :Routes, set
+ const_set :Routes, set
end
-# set up some macros
+# set up some macros and share some contexts
class ActionController::TestCase
+ include With
+
def it_redirects_to(path)
assert_redirected_to path
end
-
+
def it_assigns_flash(key, pattern)
assert flash[:error] =~ pattern
end
+
+ share :login_as_admin do
+ before { @controller.current_user = User.new(true) }
+ end
+
+ share :valid_article_params do
+ before { @params = valid_article_params }
+ end
+
+ # TODO figure out how to reduce this syntax
+ share :invalid_article_params,
+ lambda { before { @params = valid_article_params.except(:title) } },
+ lambda { before { @params = valid_article_params.except(:body) } }
end
# TODO figure out how to reduce this
@@ -81,43 +96,27 @@ def it_redirects_to(path)
# and now the fun starts ...
class ArticlesControllerTest < ActionController::TestCase
- extend With
-
def valid_article_params
{ :title => 'an article title', :body => 'an article body' }
end
-
+
describe 'POST to :create' do
action { post :create, @params }
-
+
with :login_as_admin do
it "succeeds", :with => :valid_article_params do
it_redirects_to 'articles/1'
end
-
+
it "fails", :with => :invalid_article_params do
it_assigns_flash :error, /missing: (body|title)/
end
end
-
+
with :login_as_user, :no_login do
it_redirects_to '/login'
end
-
- # TODO figure out how to move these out of here ...
- share :login_as_admin do
- before { @controller.current_user = User.new(true) }
- end
-
- share :valid_article_params do
- before { @params = valid_article_params }
- end
-
- # TODO figure out how to reduce this syntax
- share :invalid_article_params,
- lambda { before { @params = valid_article_params.except(:title) } },
- lambda { before { @params = valid_article_params.except(:body) } }
end
-
+
puts "tests defined: \n " + instance_methods.grep(/^test_/).join(", \n ")
end
@@ -1,34 +1,34 @@
require File.dirname(__FILE__) + '/test_helper'
class TestUnitWithTest < Test::Unit::TestCase
- extend With
-
+ include With
+
describe 'foo' do
action { :'called action!' }
-
+
with :'context 1', :'context 2' do
it :'assertion 1', :with => :'context 3' do
:'called assertion 1'
end
end
-
- share :'context 1' do
+
+ share :'context 1' do
before :'precondition 1' do
:'called precondition 1'
end
end
-
- share :'context 2' do
- before :'precondition 2' do
- :'called precondition 2'
- end
+ end
+
+ share :'context 2' do
+ before :'precondition 2' do
+ :'called precondition 2'
end
end
-
- @@tests_defined = instance_methods.grep(/^test_/)
+
+ @@tests_defined = instance_methods.grep(/^test_/).map{|name| name.gsub(/test_[\d]*/, 'test')}.sort
def test_with_defined_two_tests
- names = [ "test_foo_with_context_1_and_with_context_3",
+ names = [ "test_foo_with_context_1_and_with_context_3",
"test_foo_with_context_2_and_with_context_3" ]
assert_equal names, @@tests_defined
end
Oops, something went wrong.

0 comments on commit cb0918f

Please sign in to comment.