Module: Context::TestCase::ClassMethods

Defined in:
lib/context/core.rb,
lib/context/test.rb,
lib/context/suite.rb,
lib/context/lifecycle.rb,
lib/context/shared_behavior.rb,
lib/context/core_ext/rails_hacks.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#after_all_callbacksObject

Returns the value of attribute after_all_callbacks.



3
4
5
# File 'lib/context/lifecycle.rb', line 3

def after_all_callbacks
  @after_all_callbacks
end

#after_each_callbacksObject

Returns the value of attribute after_each_callbacks.



3
4
5
# File 'lib/context/lifecycle.rb', line 3

def after_each_callbacks
  @after_each_callbacks
end

#before_all_callbacksObject

Returns the value of attribute before_all_callbacks.



3
4
5
# File 'lib/context/lifecycle.rb', line 3

def before_all_callbacks
  @before_all_callbacks
end

#before_each_callbacksObject

Returns the value of attribute before_each_callbacks.



3
4
5
# File 'lib/context/lifecycle.rb', line 3

def before_each_callbacks
  @before_each_callbacks
end

#before_should_callbacksObject

Returns the value of attribute before_should_callbacks.



3
4
5
# File 'lib/context/lifecycle.rb', line 3

def before_should_callbacks
  @before_should_callbacks
end

#context_listObject

Test::Unit uses ObjectSpace to figure out what Test::Unit:TestCase instances are running Contexts are not named and therefore sometimes get garbage collected. Think of #context_list as the shelter for nameless contexts



35
36
37
# File 'lib/context/core.rb', line 35

def context_list
  @context_list
end

Class Method Details

.extended(test_case) ⇒ Object



5
6
7
8
9
10
11
# File 'lib/context/lifecycle.rb', line 5

def self.extended(test_case)
  test_case.before_all_callbacks    = []
  test_case.before_each_callbacks   = []
  test_case.after_each_callbacks    = []
  test_case.after_all_callbacks     = []
  test_case.before_should_callbacks = {}
end

Instance Method Details

#after(period = :each, &block) ⇒ Object Also known as: teardown

Add logic to run after the tests (i.e., a teardown method)

after do
  User.delete_all
end


36
37
38
39
40
41
42
43
# File 'lib/context/lifecycle.rb', line 36

def after(period = :each, &block)
  unless block_given?
    block  = period
    period = :each
  end

  send("after_#{period}_callbacks") << block
end

#before(period = :each, &block) ⇒ Object Also known as: setup

Add logic to run before the tests (i.e., a setup method)

before do
  @user = User.first
end


19
20
21
22
23
24
25
26
# File 'lib/context/lifecycle.rb', line 19

def before(period = :each, &block)
  unless block_given?
    block  = period
    period = :each
  end

  send("before_#{period}_callbacks") << block
end

#before_test(name, &block) ⇒ Object



29
30
31
# File 'lib/context/test.rb', line 29

def before_test(name, &block)
  test(name, :before => block) {}
end

#context(name, &block) ⇒ Object

Add a context to a set of tests.

context "A new account" do
  it "should not have users"
    assert Account.new.users.empty?
  end
end

The context name is prepended to the test name, so failures look like this:

1) Failure:
test_a_new_account_should_not_have_users() [./test/test_accounts.rb:4]:
<false> is not true.

Contexts can also be nested like so:

context "A new account" do
  context "created by the web application" do
    it "should have web as its vendor" do
      assert_equal "web", users(:web_user).vendor
    end
  end
end

Since contexts create a singleton instance of a class, each one must have its own before/after blocks. This will be tweaked in future releases to allow you to chain these blocks from its parent contexts.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/context/core.rb', line 75

def context(name, &block)
  cls = Class.new(self)
  cls.context_name = name

  # Care about Rails tests in nested contexts
  cls.tests($1.constantize) if defined?(Rails) && 
    self.name =~ /^(.*(Controller|Helper|Mailer))Test/ && 
      self < ActiveSupport::TestCase

  cls.class_eval(&block)
  (self.context_list ||= []) << cls
  const_set("Test#{name.to_class_name}#{cls.object_id.abs}", cls)
  cls
end

#context_nameObject

:nodoc:



37
38
39
40
41
42
# File 'lib/context/core.rb', line 37

def context_name #:nodoc:
  @context_name ||= ""
  if superclass.respond_to?(:context_name)
    return "#{superclass.context_name} #{@context_name}".gsub(/^\s+/, "")
  end
end

#context_name=(val) ⇒ Object

:nodoc:



44
45
46
# File 'lib/context/core.rb', line 44

def context_name=(val) #:nodoc:
  @context_name = val
end

#context_suiteObject

Tweaks to standard method so we don’t get superclass methods and we don’t get weird default tests



5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/context/suite.rb', line 5

def context_suite # :nodoc:
  method_names = public_instance_methods - superclass.public_instance_methods
  
  tests = method_names.delete_if {|method_name| method_name !~ /^test./}
  suite = TestSuite.new(name)
  
  tests.sort.each do |test|
    catch(:invalid_test) do
      suite << new(test)
    end
  end
  
  suite
end

#gather_callbacks(callback_type, period) ⇒ Object

:nodoc:



47
48
49
50
# File 'lib/context/lifecycle.rb', line 47

def gather_callbacks(callback_type, period) # :nodoc:
  callbacks = superclass.respond_to?(:gather_callbacks) ? superclass.gather_callbacks(callback_type, period) : []
  callbacks.push(*send("#{callback_type}_#{period}_callbacks"))
end

#inherited(child) ⇒ Object

:nodoc:



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/context/lifecycle.rb', line 52

def inherited(child) # :nodoc:
  super
  child.before_all_callbacks    = []
  child.before_each_callbacks   = []
  child.after_each_callbacks    = []
  child.after_all_callbacks     = []
  child.before_should_callbacks = {}

  child.class_eval do
    def setup(&block)
      super
      run_context_before_callbacks
    end

    def teardown
      super
      run_context_after_callbacks
    end
  end if self == ::Context.core_class
end

#setup_for_shouldaObject



2
3
4
5
6
7
# File 'lib/context/core_ext/rails_hacks.rb', line 2

def setup_for_shoulda
  self.instance_eval do
    alias :setup :before
    alias :teardown :after
  end
end

#shared(name, &block) ⇒ Object

Share behavior among different contexts. This creates a module (actually, a Module subclass) that is included using the use method (or one of its aliases) provided by context or include if you know the module’s constant name.

Examples

shared "other things" do
  it "should do things but not some things" do
    # behavior is fun
  end
end

use "other things"
# or...
it_should_behave_like "other things"

shared :client do
  it "should be a client to our server" do
    # TODO: client behavior here
  end
end

use :client
# or...
uses "client"
behaves_like "client"


48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/context/shared_behavior.rb', line 48

def shared(name, &block)
  case name.class.name
  when "String"
    name = name.to_module_name
  when "Symbol"
    name = name.to_s.to_module_name
  else
    raise ArgumentError, "Provide a String or Symbol as the name of the shared behavior group"
  end
  
  Object.const_set(name, Context::SharedBehavior.create_from_behavior(block))
end

#test(name, opts = {}, &block) ⇒ Object

Create a test method. name is a native-language string to describe the test (e.g., no more test_this_crazy_thing_with_underscores).

test "A user should not be able to delete another user" do
  assert_false @user.can?(:delete, @other_user)
end


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/context/test.rb', line 9

def test(name, opts={}, &block)
  test_name = ["test:", context_name, name].reject { |n| n == "" }.join(' ')
  defined = instance_method(test_name) rescue false
  raise "#{test_name} is already defined in #{self}" if defined

  unless opts[:before].nil?
    before_should_callbacks[test_name] = opts[:before]
  end
  
  if block_given?
    define_method(test_name, &block)
  else
    define_method(test_name) do
      flunk "No implementation provided for #{name}"
    end
  end
end

#use(shared_name) ⇒ Object

Pull in behavior shared by shared or a module.

Examples

shared "other things" do
  it "should do things but not some things" do
    # behavior is fun
  end
end

use "other things"
# or...
it_should_behave_like "other things"

module Things
end

uses Things


82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/context/shared_behavior.rb', line 82

def use(shared_name)
  case shared_name.class.name
  when "Context::SharedBehavior", "Module"
    include shared_name
  when "String"
    include Object.const_get(shared_name.to_module_name)
  when "Symbol"
    include Object.const_get(shared_name.to_s.to_module_name)
  else
    raise ArgumentError, "Provide a String or Symbol as the name of the shared behavior group or the module name"
  end
end