Class: Arrow::AppletTestCase

Inherits:
Test::Unit::TestCase
  • Object
show all
Includes:
Loggable, FlexMock::TestCase, Test::Unit::Assertions
Defined in:
lib/arrow/applettestcase.rb

Overview

This is an abstract test case class for building Test::Unit unit tests for Arrow applets.

Synopsis

$LOAD_PATH.unshift “tests/lib” unless $LOAD_PATH.include?(“tests/lib”) require ‘applettestcase’

class MySomethingTest < Arrow::AppletTestCase

  applet_under_test "jobs"

  def test_default_request_should_return_object_list
    
  end

  def test_default_request_with_oid_arg_should_display_details
    set_request_params :oid => 13
  end

end

VCS Id

 $Id$

Authors

  • Michael Granger

Copyright © 2003, 2004, 2006 RubyCrafters, LLC.

This work is licensed under the Creative Commons Attribution License. To view a copy of this license, visit creativecommons.org/licenses/by/1.0 or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.

Constant Summary

APPLET_PATH =

The default path to the directory where applets live

Pathname.new( $0 ).expand_path.dirname + "applets"
AnsiAttributes =

Set some ANSI escape code constants (Shamelessly stolen from Perl’s Term::ANSIColor by Russ Allbery and Zenin

{
  'clear'      => 0,
  'reset'      => 0,
  'bold'       => 1,
  'dark'       => 2,
  'underline'  => 4,
  'underscore' => 4,
  'blink'      => 5,
  'reverse'    => 7,
  'concealed'  => 8,

  'black'      => 30,   'on_black'   => 40, 
  'red'        => 31,   'on_red'     => 41, 
  'green'      => 32,   'on_green'   => 42, 
  'yellow'     => 33,   'on_yellow'  => 43, 
  'blue'       => 34,   'on_blue'    => 44, 
  'magenta'    => 35,   'on_magenta' => 45, 
  'cyan'       => 36,   'on_cyan'    => 46, 
  'white'      => 37,   'on_white'   => 47
}

Class Attribute Summary

Class Method Summary

Instance Method Summary

Methods included from Loggable

#log

Constructor Details

- (AppletTestCase) initialize(*args)

Check to be sure an applet has been associated before instantiation.



239
240
241
242
# File 'lib/arrow/applettestcase.rb', line 239

def initialize( *args ) # :notnew:
    throw :invalid_test unless self.class.appletclass
    super
end

Class Attribute Details

+ (Object) appletclass

Returns the value of attribute appletclass



96
97
98
# File 'lib/arrow/applettestcase.rb', line 96

def appletclass
  @appletclass
end

+ (Object) appletname

Returns the value of attribute appletname



96
97
98
# File 'lib/arrow/applettestcase.rb', line 96

def appletname
  @appletname
end

+ (Object) fixture_data

Returns the value of attribute fixture_data



96
97
98
# File 'lib/arrow/applettestcase.rb', line 96

def fixture_data
  @fixture_data
end

Class Method Details

+ (Object) ansicode(*attributes)

Returns a String containing the specified ANSI escapes suitable for inclusion in another string. The attributes should be one or more of the keys of AnsiAttributes.



127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/arrow/applettestcase.rb', line 127

def self::ansicode( *attributes )
  return '' unless /(?:xterm(?:-color)?|eterm|linux)/i =~ ENV['TERM']

  attr = attributes.collect {|a|
    AnsiAttributes[a] ? AnsiAttributes[a] : nil
  }.compact.join(';')
  if attr.empty? 
    return ''
  else
    return "\e[%sm" % attr
  end
end

+ (Object) applet_under_test(applet)

Define the name of the applet under test. The given name will be stringified, downcased, and searched for in the #applet_path.



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/arrow/applettestcase.rb', line 201

def self::applet_under_test( applet )
  if applet.is_a?( Class )
    self.appletclass = applet
    self.appletname = applet.signature.name
  else
    debug_msg "Setting applet under test for testcase: %p" % [self]

    if Arrow::Applet.derivatives.empty?
            Pathname.glob( APPLET_PATH + '**/*.rb' ).each do |appletfile|
           debug_msg "Trying to load #{appletfile}"
        begin
          Arrow::Applet.load( appletfile )
        rescue LoadError
        end
         end
        end

    # :view_template becomes /view[-_]template/
    applet_pat = Regexp.new( applet.to_s.gsub(/_/, '[-_]?') )
  
    self.appletclass = Arrow::Applet.derivatives.find {|klass|
      debug_msg "  Checking applet '#{klass.name.downcase}' =~ #{applet_pat}..."
      applet_pat.match( klass.name.downcase ) or
        applet_pat.match( klass.filename )
    } or raise "Failed to load applet matching #{applet_pat}"
    self.appletname = applet.to_s

    debug_msg "Applet under test is: #{self.appletclass}"
  end
end

+ (Object) debug_msg(*msgs)

Output the specified msgs joined together to STDERR if $DEBUG is set.



143
144
145
146
147
# File 'lib/arrow/applettestcase.rb', line 143

def self::debug_msg( *msgs )
  return unless $DEBUG
  self.message "%sDEBUG>>> %s %s" %
    [ ansicode('dark', 'white'), msgs.join(''), ansicode('reset') ]
end

+ (Object) message(*msgs)

Output the specified msgs joined together to STDOUT.



152
153
154
155
# File 'lib/arrow/applettestcase.rb', line 152

def self::message( *msgs )
  $stderr.puts msgs.join('')
  $stderr.flush
end

+ (Object) set_fixture_data(model_class, data)

Set up model data for the given model_class that can be used in the stub data classes. The data argument is an Array of data, and can be either Hashes or Arrays. If Arrays are used, the first one in the list should be a list of fields, and each subsequent Array should be field values. E.g.,

  [
    [ :title, :description, :date ],
    [ "title1", "desc1",    Date.today ],
    [ "title2", "desc2",    Date.today-4 ],
  ]

which is equivalent to:

  [
    { :title => "title1", :description => "desc1", :date => Date.today }
    { :title => "title1", :description => "desc1", :date => Date.today }
  ]


173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/arrow/applettestcase.rb', line 173

def self::set_fixture_data( model_class, data )
    @fixture_data ||= {}
    
# [ [<fields>], [<values1], [<values2>] ]
    if data.first.is_a?( Array )
  fields = data.shift
  objects = data.collect do |row|
    obj = OpenStruct.new
    fields.each_with_index {|f,i| obj.__send__(f, row[i])}
  end

# [ {:field1 => <value1>}, {:field1 => <value2>} ]
elsif data.first.is_a?( Hash )
  objects = data.collect do |row|
    OpenStruct.new( row )
  end

# Custom objects (Mocks, etc.)
elsif data.is_a?( Array )
  objects = data
end 
    
    @fixture_data[ model_class ] = objects
end

Instance Method Details

- (Object) ansicode(*attributes)

Instance-alias for the like-named class method



298
299
300
# File 'lib/arrow/applettestcase.rb', line 298

def ansicode( *attributes )
  self.class.ansicode( *attributes )
end

- (Object) create_mock(name)

Create a new mock object and register it to be verified at the end of the test.



469
470
471
# File 'lib/arrow/applettestcase.rb', line 469

def create_mock( name )
      return flexmock( name )
end

- (Object) debug_msg(*msgs)

Instance alias for the like-named class method



304
305
306
# File 'lib/arrow/applettestcase.rb', line 304

def debug_msg( *msgs )
  self.class.debug_msg( *msgs )
end

- (Object) default_delegation_behavior

The default block passed to Arrow::Applet#delegate by #with_fixtured_delegation if no block is passed to either #should_delegate or #should_not_delegate. If you override this, you should either super to this method or set @delegate_called yourself.



412
413
414
# File 'lib/arrow/applettestcase.rb', line 412

def default_delegation_behavior
  @delegate_called = true
end

- (Object) extract_parameters(queryhash, key = nil)

Extract parameters for the given key from the given queryhash using the form validator for the current action and return it.



488
489
490
491
492
493
494
495
496
497
498
499
500
# File 'lib/arrow/applettestcase.rb', line 488

def extract_parameters( queryhash, key=nil )
  profile = @applet.signature.validator_profiles[ @action ] ||
    @applet.signature_profiles[ :__default__ ]
  validator = Arrow::FormValidator.new( profile )
  
  validator.validate( queryhash )

  if key
    return validator.valid[ key ]
  else
    return validator.valid
  end
end

- (Object) fixture_session(txn)

Set up a mock object as the given transaction’s session.



475
476
477
478
479
480
481
482
483
# File 'lib/arrow/applettestcase.rb', line 475

def fixture_session( txn )
  session = create_mock( "session" )
  txn.should_receive( :session ).
      and_return( session ).zero_or_more_times
  session.should_receive( :[] ).and_return( nil ).zero_or_more_times
  session.should_receive( :[]= ).and_return( nil ).zero_or_more_times
  
  return session
end

- (Object) hrule(length = 75, char = "-")

Return a separator line made up of length of the specified char.



311
312
313
# File 'lib/arrow/applettestcase.rb', line 311

def hrule( length=75, char="-" )
  return (char * length ) + "\n"
end

- (Object) hrule_section(content, caption = '')

Return a section delimited by hrules with the specified caption and content.



317
318
319
320
321
322
323
# File 'lib/arrow/applettestcase.rb', line 317

def hrule_section( content, caption='' )
  caption << ' ' unless caption.empty?
  return caption +
    hrule( 75 - caption.length ) +
    content.chomp + "\n" +
    hrule()
end

- (Object) message(*msgs)

Instance alias for the like-named class method.



292
293
294
# File 'lib/arrow/applettestcase.rb', line 292

def message( *msgs )
  self.class.message( *msgs )
end

Output a header for delimiting tests



327
328
329
330
331
# File 'lib/arrow/applettestcase.rb', line 327

def print_test_header( desc )
  return unless $VERBOSE || $DEBUG
  message "%s>>> %s <<<%s" % 
    [ ansicode('bold','yellow','on_blue'), desc, ansicode('reset') ]
end

- (Object) run(result)

Output the name of the test as it’s running if in verbose mode, and support per-test debugging settings.



280
281
282
283
# File 'lib/arrow/applettestcase.rb', line 280

def run( result )
  print_test_header self.name
  super
end

- (Object) setup

Set up a test with some useful test objects



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/arrow/applettestcase.rb', line 246

def setup
  super

  debug_msg "%p: Setting up test for applet %p" % 
    [self.class, self.class.appletclass]

  # Give the test an easy reference to the applet class under test
  @appletclass = self.class.appletclass or
    raise "No applet defined for '#{self.class.name}'. Add " +
      "'applet_under_test :<appletname>' to correct this."
  @appletname = self.class.appletname
  @action = nil
  
  @config = flexmock( "mock config" )
  @config.should_receive( :symbolize_keys ).and_return({})
  @config.should_receive( :member? ).
    with( :db ).
    and_return( false )
  @config.should_receive( :name ).and_return( "mock" )
  @config.should_receive( :member? ).
    with( :model ).
    and_return( false )
  @config.should_ignore_missing
  @template_factory = flexmock( "mock template factory" )

  @applet = @appletclass.new( @config, @template_factory, "#{@appletname}" )

  @delegate_behavior = nil
  @delegate_should_be_called = true
  @delegate_called = false
end

- (Object) setup_fixtured_request(action, *args)

Set up faked request and transaction objects for the given action, using the given args as REST-style arguments, and/or query arguments if the last element is a Hash.



420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
# File 'lib/arrow/applettestcase.rb', line 420

def setup_fixtured_request( action, *args )
  uri = '/' + File.join( @appletname, action.to_s )
  req = Apache::Request.new( uri )

  params = args.last.is_a?( Hash ) ? args.pop : {}
  debug_msg "Parameters hash set to: %p" % [params]
  req.paramtable = params

  debug_msg "Request is: %p" % [req]
  #txn = Arrow::Transaction.new( req, @config, nil )
  txn = flexmock( "transaction" )
  txn.should_receive( :request ).
      and_return( req ).zero_or_more_times
  txn.should_receive( :vargs= ).
      with( Arrow::FormValidator ).zero_or_more_times
  
  vargs = flexmock( "form validator" )
  txn.should_receive( :vargs ).
    and_return( vargs ).
    zero_or_more_times
  vargs.should_receive( :[] ).zero_or_more_times
  
  debug_msg "Transaction is: %p" % [txn]
  return txn, req, vargs, *args
end

- (Object) should_delegate(&block)

The default delegate block — call this from within your #with_fixtured_delegation block if the applet under test should delegate to the next applet in the chain.



391
392
393
394
395
# File 'lib/arrow/applettestcase.rb', line 391

def should_delegate( &block )
  @delegate_should_be_called = true
  @delegate_behavior = block || 
    method( :default_delegation_behavior ).to_proc
end

- (Object) should_load_template(key) {|mock_template| ... }

Assert that the current action should load the template associated with the given key, and passes a mock template object to the given block for further specification.

Yields:

  • (mock_template)


450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
# File 'lib/arrow/applettestcase.rb', line 450

def should_load_template( key )
  tname = @applet.signature.templates[ key ] or
    raise Test::Unit::AssertionFailedError.new(
      "Expected applet to load the '#{key.inspect}' template\n" +
      "but there was no such template registered by the application." )
  
  mock_template = flexmock( "#{key.inspect} template")
  @template_factory.should_receive( :get_template ).
    with( tname ).and_return( mock_template ).at_least.once
  mock_template.should_ignore_missing

  yield( mock_template ) if block_given?
  
  return mock_template
end

- (Object) should_not_delegate(&block)

Negated delegate block — call this at the end of your #with_fixtured_delegation block if the applet under test should not delegate to the next applet in the chain.



401
402
403
404
405
# File 'lib/arrow/applettestcase.rb', line 401

def should_not_delegate( &block )
  @delegate_should_be_called = false
  @delegate_behavior = block || 
    method( :default_delegation_behavior ).to_proc
end

- (Object) with_fixtured_action(action = nil, *args, &block)

Set up faked request and transaction objects, yield to the given block with them, then run the applet under test with them when the block returns.



341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/arrow/applettestcase.rb', line 341

def with_fixtured_action( action=nil, *args, &block )
  @action = action
  txn, req, vargs, *args = setup_fixtured_request( action, *args )
  
  if block.arity == 3
    block.call( txn, req, vargs )
  else
    block.call( txn, req )
  end
  
  return @applet.run( txn, action.to_s, *args )
ensure
  @action = nil
end

- (Object) with_fixtured_delegation(chain = [], *args, &block)

Set up a faked request and transaction object, yield to the given block with them, and then call the #delegate method of the applet under test. Unless otherwise indicated (via a call to #should_not_delegate), the expectation will be set up that the applet under test should call its delegate.



362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'lib/arrow/applettestcase.rb', line 362

def with_fixtured_delegation( chain=[], *args, &block )
  txn, req, vargs, *args = setup_fixtured_request( "delegated_action", *args )

  # Set delegation expectation
  @delegate_behavior ||= should_delegate()

  if block.arity == 3
    block.call( txn, req, vargs )
  else
    block.call( txn, req )
  end
  
  rval = @applet.delegate( txn, chain, *args, &@delegate_behavior )
  
  if @delegate_should_be_called
    assert @delegate_called,
      "delegate applet was never called" 
  else
    assert !@delegate_called,
      "delegate applet was called unexpectedly"
  end

  return rval
end