aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/test/cases
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2009-03-20 10:32:24 +0000
committerPratik Naik <pratiknaik@gmail.com>2009-03-20 10:32:24 +0000
commit5b1a1bf5bfc520248285b036672146122dd2a815 (patch)
tree31d82a9155db6c9e553888da6375bd89fdb122cf /activemodel/test/cases
parent93e2d378df5f599e3e48e74932f37e1c679f633e (diff)
downloadrails-5b1a1bf5bfc520248285b036672146122dd2a815.tar.gz
rails-5b1a1bf5bfc520248285b036672146122dd2a815.tar.bz2
rails-5b1a1bf5bfc520248285b036672146122dd2a815.zip
Make Active Model test suite similar to Active Record
Diffstat (limited to 'activemodel/test/cases')
-rw-r--r--activemodel/test/cases/helper.rb38
-rw-r--r--activemodel/test/cases/observing_test.rb121
-rw-r--r--activemodel/test/cases/state_machine/event_test.rb49
-rw-r--r--activemodel/test/cases/state_machine/machine_test.rb43
-rw-r--r--activemodel/test/cases/state_machine/state_test.rb72
-rw-r--r--activemodel/test/cases/state_machine/state_transition_test.rb84
-rw-r--r--activemodel/test/cases/state_machine_test.rb312
7 files changed, 719 insertions, 0 deletions
diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb
new file mode 100644
index 0000000000..6465f4e61f
--- /dev/null
+++ b/activemodel/test/cases/helper.rb
@@ -0,0 +1,38 @@
+$:.unshift(File.dirname(__FILE__) + '/../../lib')
+$:.unshift(File.dirname(__FILE__) + '/../../../activerecord/lib')
+$:.unshift(File.dirname(__FILE__) + '/../../../activesupport/lib')
+
+require 'config'
+require 'active_model'
+
+require 'active_record'
+require 'logger'
+ActiveRecord::Base.logger = Logger.new("debug.log")
+
+class SqliteError < StandardError
+end
+
+# Setup database connection
+db_file = "#{FIXTURES_ROOT}/fixture_database.sqlite3"
+ActiveRecord::Base.configurations = { ActiveRecord::Base.name => { :adapter => 'sqlite3', :database => db_file, :timeout => 5000 } }
+unless File.exist?(db_file)
+ puts "SQLite3 database not found at #{db_file}. Rebuilding it."
+ sqlite_command = %Q{sqlite3 "#{db_file}" "create table a (a integer); drop table a;"}
+ puts "Executing '#{sqlite_command}'"
+ raise SqliteError.new("Seems that there is no sqlite3 executable available") unless system(sqlite_command)
+end
+ActiveRecord::Base.establish_connection(ActiveRecord::Base.name)
+
+# Show backtraces for deprecated behavior for quicker cleanup.
+ActiveSupport::Deprecation.debug = true
+
+require 'rubygems'
+require 'test/unit'
+gem 'mocha', '>= 0.9.5'
+require 'mocha'
+
+begin
+ require 'ruby-debug'
+ Debugger.start
+rescue LoadError
+end
diff --git a/activemodel/test/cases/observing_test.rb b/activemodel/test/cases/observing_test.rb
new file mode 100644
index 0000000000..421ac4b4f8
--- /dev/null
+++ b/activemodel/test/cases/observing_test.rb
@@ -0,0 +1,121 @@
+require 'cases/helper'
+
+class ObservedModel < ActiveModel::Base
+ class Observer
+ end
+end
+
+class FooObserver < ActiveModel::Observer
+ class << self
+ public :new
+ end
+
+ attr_accessor :stub
+
+ def on_spec(record)
+ stub.event_with(record) if stub
+ end
+end
+
+class Foo < ActiveModel::Base
+end
+
+class ObservingTest < ActiveModel::TestCase
+ def setup
+ ObservedModel.observers.clear
+ end
+
+ test "initializes model with no cached observers" do
+ assert ObservedModel.observers.empty?, "Not empty: #{ObservedModel.observers.inspect}"
+ end
+
+ test "stores cached observers in an array" do
+ ObservedModel.observers << :foo
+ assert ObservedModel.observers.include?(:foo), ":foo not in #{ObservedModel.observers.inspect}"
+ end
+
+ test "flattens array of assigned cached observers" do
+ ObservedModel.observers = [[:foo], :bar]
+ assert ObservedModel.observers.include?(:foo), ":foo not in #{ObservedModel.observers.inspect}"
+ assert ObservedModel.observers.include?(:bar), ":bar not in #{ObservedModel.observers.inspect}"
+ end
+
+ test "instantiates observer names passed as strings" do
+ ObservedModel.observers << 'foo_observer'
+ FooObserver.expects(:instance)
+ ObservedModel.instantiate_observers
+ end
+
+ test "instantiates observer names passed as symbols" do
+ ObservedModel.observers << :foo_observer
+ FooObserver.expects(:instance)
+ ObservedModel.instantiate_observers
+ end
+
+ test "instantiates observer classes" do
+ ObservedModel.observers << ObservedModel::Observer
+ ObservedModel::Observer.expects(:instance)
+ ObservedModel.instantiate_observers
+ end
+
+ test "passes observers to subclasses" do
+ FooObserver.instance
+ bar = Class.new(Foo)
+ assert_equal Foo.count_observers, bar.count_observers
+ end
+end
+
+class ObserverTest < ActiveModel::TestCase
+ def setup
+ ObservedModel.observers = :foo_observer
+ FooObserver.models = nil
+ end
+
+ test "guesses implicit observable model name" do
+ assert_equal 'Foo', FooObserver.observed_class_name
+ end
+
+ test "tracks implicit observable models" do
+ instance = FooObserver.new
+ assert instance.send(:observed_classes).include?(Foo), "Foo not in #{instance.send(:observed_classes).inspect}"
+ assert !instance.send(:observed_classes).include?(ObservedModel), "ObservedModel in #{instance.send(:observed_classes).inspect}"
+ end
+
+ test "tracks explicit observed model class" do
+ old_instance = FooObserver.new
+ assert !old_instance.send(:observed_classes).include?(ObservedModel), "ObservedModel in #{old_instance.send(:observed_classes).inspect}"
+ FooObserver.observe ObservedModel
+ instance = FooObserver.new
+ assert instance.send(:observed_classes).include?(ObservedModel), "ObservedModel not in #{instance.send(:observed_classes).inspect}"
+ end
+
+ test "tracks explicit observed model as string" do
+ old_instance = FooObserver.new
+ assert !old_instance.send(:observed_classes).include?(ObservedModel), "ObservedModel in #{old_instance.send(:observed_classes).inspect}"
+ FooObserver.observe 'observed_model'
+ instance = FooObserver.new
+ assert instance.send(:observed_classes).include?(ObservedModel), "ObservedModel not in #{instance.send(:observed_classes).inspect}"
+ end
+
+ test "tracks explicit observed model as symbol" do
+ old_instance = FooObserver.new
+ assert !old_instance.send(:observed_classes).include?(ObservedModel), "ObservedModel in #{old_instance.send(:observed_classes).inspect}"
+ FooObserver.observe :observed_model
+ instance = FooObserver.new
+ assert instance.send(:observed_classes).include?(ObservedModel), "ObservedModel not in #{instance.send(:observed_classes).inspect}"
+ end
+
+ test "calls existing observer event" do
+ foo = Foo.new
+ FooObserver.instance.stub = stub
+ FooObserver.instance.stub.expects(:event_with).with(foo)
+ Foo.send(:changed)
+ Foo.send(:notify_observers, :on_spec, foo)
+ end
+
+ test "skips nonexistent observer event" do
+ foo = Foo.new
+ Foo.send(:changed)
+ Foo.send(:notify_observers, :whatever, foo)
+ end
+end
diff --git a/activemodel/test/cases/state_machine/event_test.rb b/activemodel/test/cases/state_machine/event_test.rb
new file mode 100644
index 0000000000..2a0ef53a3f
--- /dev/null
+++ b/activemodel/test/cases/state_machine/event_test.rb
@@ -0,0 +1,49 @@
+require 'cases/helper'
+
+class EventTest < ActiveModel::TestCase
+ def setup
+ @state_name = :close_order
+ @success = :success_callback
+ end
+
+ def new_event
+ @event = ActiveModel::StateMachine::Event.new(nil, @state_name, {:success => @success}) do
+ transitions :to => :closed, :from => [:open, :received]
+ end
+ end
+
+ test 'should set the name' do
+ assert_equal @state_name, new_event.name
+ end
+
+ test 'should set the success option' do
+ assert_equal @success, new_event.success
+ end
+
+ test 'should create StateTransitions' do
+ ActiveModel::StateMachine::StateTransition.expects(:new).with(:to => :closed, :from => :open)
+ ActiveModel::StateMachine::StateTransition.expects(:new).with(:to => :closed, :from => :received)
+ new_event
+ end
+end
+
+class EventBeingFiredTest < ActiveModel::TestCase
+ test 'should raise an AASM::InvalidTransition error if the transitions are empty' do
+ event = ActiveModel::StateMachine::Event.new(nil, :event)
+
+ assert_raise ActiveModel::StateMachine::InvalidTransition do
+ event.fire(nil)
+ end
+ end
+
+ test 'should return the state of the first matching transition it finds' do
+ event = ActiveModel::StateMachine::Event.new(nil, :event) do
+ transitions :to => :closed, :from => [:open, :received]
+ end
+
+ obj = stub
+ obj.stubs(:current_state).returns(:open)
+
+ assert_equal :closed, event.fire(obj)
+ end
+end
diff --git a/activemodel/test/cases/state_machine/machine_test.rb b/activemodel/test/cases/state_machine/machine_test.rb
new file mode 100644
index 0000000000..2aa954d80c
--- /dev/null
+++ b/activemodel/test/cases/state_machine/machine_test.rb
@@ -0,0 +1,43 @@
+require 'cases/helper'
+
+class MachineTestSubject
+ include ActiveModel::StateMachine
+
+ state_machine do
+ state :open
+ state :closed
+ end
+
+ state_machine :initial => :foo do
+ event :shutdown do
+ transitions :from => :open, :to => :closed
+ end
+
+ event :timeout do
+ transitions :from => :open, :to => :closed
+ end
+ end
+
+ state_machine :extra, :initial => :bar do
+ end
+end
+
+class StateMachineMachineTest < ActiveModel::TestCase
+ test "allows reuse of existing machines" do
+ assert_equal 2, MachineTestSubject.state_machines.size
+ end
+
+ test "sets #initial_state from :initial option" do
+ assert_equal :bar, MachineTestSubject.state_machine(:extra).initial_state
+ end
+
+ test "accesses non-default state machine" do
+ assert_kind_of ActiveModel::StateMachine::Machine, MachineTestSubject.state_machine(:extra)
+ end
+
+ test "finds events for given state" do
+ events = MachineTestSubject.state_machine.events_for(:open)
+ assert events.include?(:shutdown)
+ assert events.include?(:timeout)
+ end
+end
diff --git a/activemodel/test/cases/state_machine/state_test.rb b/activemodel/test/cases/state_machine/state_test.rb
new file mode 100644
index 0000000000..527bfd4c04
--- /dev/null
+++ b/activemodel/test/cases/state_machine/state_test.rb
@@ -0,0 +1,72 @@
+require 'cases/helper'
+
+class StateTestSubject
+ include ActiveModel::StateMachine
+
+ state_machine do
+ end
+end
+
+class StateTest < ActiveModel::TestCase
+ def setup
+ @state_name = :astate
+ @machine = StateTestSubject.state_machine
+ @options = { :crazy_custom_key => 'key', :machine => @machine }
+ end
+
+ def new_state(options={})
+ ActiveModel::StateMachine::State.new(@state_name, @options.merge(options))
+ end
+
+ test 'sets the name' do
+ assert_equal :astate, new_state.name
+ end
+
+ test 'sets the display_name from name' do
+ assert_equal "Astate", new_state.display_name
+ end
+
+ test 'sets the display_name from options' do
+ assert_equal "A State", new_state(:display => "A State").display_name
+ end
+
+ test 'sets the options and expose them as options' do
+ @options.delete(:machine)
+ assert_equal @options, new_state.options
+ end
+
+ test 'equals a symbol of the same name' do
+ assert_equal new_state, :astate
+ end
+
+ test 'equals a State of the same name' do
+ assert_equal new_state, new_state
+ end
+
+ test 'should send a message to the record for an action if the action is present as a symbol' do
+ state = new_state(:entering => :foo)
+
+ record = stub
+ record.expects(:foo)
+
+ state.call_action(:entering, record)
+ end
+
+ test 'should send a message to the record for an action if the action is present as a string' do
+ state = new_state(:entering => 'foo')
+
+ record = stub
+ record.expects(:foo)
+
+ state.call_action(:entering, record)
+ end
+
+ test 'should call a proc, passing in the record for an action if the action is present' do
+ state = new_state(:entering => Proc.new {|r| r.foobar})
+
+ record = stub
+ record.expects(:foobar)
+
+ state.call_action(:entering, record)
+ end
+end
diff --git a/activemodel/test/cases/state_machine/state_transition_test.rb b/activemodel/test/cases/state_machine/state_transition_test.rb
new file mode 100644
index 0000000000..17f9d88be7
--- /dev/null
+++ b/activemodel/test/cases/state_machine/state_transition_test.rb
@@ -0,0 +1,84 @@
+require 'cases/helper'
+
+class StateTransitionTest < ActiveModel::TestCase
+ test 'should set from, to, and opts attr readers' do
+ opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
+ st = ActiveModel::StateMachine::StateTransition.new(opts)
+
+ assert_equal opts[:from], st.from
+ assert_equal opts[:to], st.to
+ assert_equal opts, st.options
+ end
+
+ test 'should pass equality check if from and to are the same' do
+ opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
+ st = ActiveModel::StateMachine::StateTransition.new(opts)
+
+ obj = stub
+ obj.stubs(:from).returns(opts[:from])
+ obj.stubs(:to).returns(opts[:to])
+
+ assert_equal st, obj
+ end
+
+ test 'should fail equality check if from are not the same' do
+ opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
+ st = ActiveModel::StateMachine::StateTransition.new(opts)
+
+ obj = stub
+ obj.stubs(:from).returns('blah')
+ obj.stubs(:to).returns(opts[:to])
+
+ assert_not_equal st, obj
+ end
+
+ test 'should fail equality check if to are not the same' do
+ opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
+ st = ActiveModel::StateMachine::StateTransition.new(opts)
+
+ obj = stub
+ obj.stubs(:from).returns(opts[:from])
+ obj.stubs(:to).returns('blah')
+
+ assert_not_equal st, obj
+ end
+end
+
+class StateTransitionGuardCheckTest < ActiveModel::TestCase
+ test 'should return true of there is no guard' do
+ opts = {:from => 'foo', :to => 'bar'}
+ st = ActiveModel::StateMachine::StateTransition.new(opts)
+
+ assert st.perform(nil)
+ end
+
+ test 'should call the method on the object if guard is a symbol' do
+ opts = {:from => 'foo', :to => 'bar', :guard => :test_guard}
+ st = ActiveModel::StateMachine::StateTransition.new(opts)
+
+ obj = stub
+ obj.expects(:test_guard)
+
+ st.perform(obj)
+ end
+
+ test 'should call the method on the object if guard is a string' do
+ opts = {:from => 'foo', :to => 'bar', :guard => 'test_guard'}
+ st = ActiveModel::StateMachine::StateTransition.new(opts)
+
+ obj = stub
+ obj.expects(:test_guard)
+
+ st.perform(obj)
+ end
+
+ test 'should call the proc passing the object if the guard is a proc' do
+ opts = {:from => 'foo', :to => 'bar', :guard => Proc.new {|o| o.test_guard}}
+ st = ActiveModel::StateMachine::StateTransition.new(opts)
+
+ obj = stub
+ obj.expects(:test_guard)
+
+ st.perform(obj)
+ end
+end
diff --git a/activemodel/test/cases/state_machine_test.rb b/activemodel/test/cases/state_machine_test.rb
new file mode 100644
index 0000000000..f66299741e
--- /dev/null
+++ b/activemodel/test/cases/state_machine_test.rb
@@ -0,0 +1,312 @@
+require 'cases/helper'
+
+class StateMachineSubject
+ include ActiveModel::StateMachine
+
+ state_machine do
+ state :open, :exit => :exit
+ state :closed, :enter => :enter
+
+ event :close, :success => :success_callback do
+ transitions :to => :closed, :from => [:open]
+ end
+
+ event :null do
+ transitions :to => :closed, :from => [:open], :guard => :always_false
+ end
+ end
+
+ state_machine :bar do
+ state :read
+ state :ended
+
+ event :foo do
+ transitions :to => :ended, :from => [:read]
+ end
+ end
+
+ def always_false
+ false
+ end
+
+ def success_callback
+ end
+
+ def enter
+ end
+ def exit
+ end
+end
+
+class StateMachineSubjectSubclass < StateMachineSubject
+end
+
+class StateMachineClassLevelTest < ActiveModel::TestCase
+ test 'defines a class level #state_machine method on its including class' do
+ assert StateMachineSubject.respond_to?(:state_machine)
+ end
+
+ test 'defines a class level #state_machines method on its including class' do
+ assert StateMachineSubject.respond_to?(:state_machines)
+ end
+
+ test 'class level #state_machine returns machine instance' do
+ assert_kind_of ActiveModel::StateMachine::Machine, StateMachineSubject.state_machine
+ end
+
+ test 'class level #state_machine returns machine instance with given name' do
+ assert_kind_of ActiveModel::StateMachine::Machine, StateMachineSubject.state_machine(:default)
+ end
+
+ test 'class level #state_machines returns hash of machine instances' do
+ assert_kind_of ActiveModel::StateMachine::Machine, StateMachineSubject.state_machines[:default]
+ end
+
+ test "should return a select friendly array of states in the form of [['Friendly name', 'state_name']]" do
+ assert_equal [['Open', 'open'], ['Closed', 'closed']], StateMachineSubject.state_machine.states_for_select
+ end
+end
+
+class StateMachineInstanceLevelTest < ActiveModel::TestCase
+ def setup
+ @foo = StateMachineSubject.new
+ end
+
+ test 'defines an accessor for the current state' do
+ assert @foo.respond_to?(:current_state)
+ end
+
+ test 'defines a state querying instance method on including class' do
+ assert @foo.respond_to?(:open?)
+ end
+
+ test 'defines an event! instance method' do
+ assert @foo.respond_to?(:close!)
+ end
+
+ test 'defines an event instance method' do
+ assert @foo.respond_to?(:close)
+ end
+end
+
+class StateMachineInitialStatesTest < ActiveModel::TestCase
+ def setup
+ @foo = StateMachineSubject.new
+ end
+
+ test 'sets the initial state' do
+ assert_equal :open, @foo.current_state
+ end
+
+ test '#open? should be initially true' do
+ assert @foo.open?
+ end
+
+ test '#closed? should be initially false' do
+ assert !@foo.closed?
+ end
+
+ test 'uses the first state defined if no initial state is given' do
+ assert_equal :read, @foo.current_state(:bar)
+ end
+end
+
+class StateMachineEventFiringWithPersistenceTest < ActiveModel::TestCase
+ def setup
+ @subj = StateMachineSubject.new
+ end
+
+ test 'updates the current state' do
+ @subj.close!
+
+ assert_equal :closed, @subj.current_state
+ end
+
+ test 'fires the Event' do
+ @subj.class.state_machine.events[:close].expects(:fire).with(@subj)
+ @subj.close!
+ end
+
+ test 'calls the success callback if one was provided' do
+ @subj.expects(:success_callback)
+ @subj.close!
+ end
+
+ test 'attempts to persist if write_state is defined' do
+ def @subj.write_state
+ end
+
+ @subj.expects(:write_state)
+ @subj.close!
+ end
+end
+
+class StateMachineEventFiringWithoutPersistence < ActiveModel::TestCase
+ test 'updates the current state' do
+ subj = StateMachineSubject.new
+ assert_equal :open, subj.current_state
+ subj.close
+ assert_equal :closed, subj.current_state
+ end
+
+ test 'fires the Event' do
+ subj = StateMachineSubject.new
+
+ StateMachineSubject.state_machine.events[:close].expects(:fire).with(subj)
+ subj.close
+ end
+
+ test 'attempts to persist if write_state is defined' do
+ subj = StateMachineSubject.new
+
+ def subj.write_state
+ end
+
+ subj.expects(:write_state_without_persistence)
+
+ subj.close
+ end
+end
+
+class StateMachinePersistenceTest < ActiveModel::TestCase
+ test 'reads the state if it has not been set and read_state is defined' do
+ subj = StateMachineSubject.new
+ def subj.read_state
+ end
+
+ subj.expects(:read_state).with(StateMachineSubject.state_machine)
+
+ subj.current_state
+ end
+end
+
+class StateMachineEventCallbacksTest < ActiveModel::TestCase
+ test 'should call aasm_event_fired if defined and successful for bang fire' do
+ subj = StateMachineSubject.new
+ def subj.aasm_event_fired(from, to)
+ end
+
+ subj.expects(:event_fired)
+
+ subj.close!
+ end
+
+ test 'should call aasm_event_fired if defined and successful for non-bang fire' do
+ subj = StateMachineSubject.new
+ def subj.aasm_event_fired(from, to)
+ end
+
+ subj.expects(:event_fired)
+
+ subj.close
+ end
+
+ test 'should call aasm_event_failed if defined and transition failed for bang fire' do
+ subj = StateMachineSubject.new
+ def subj.event_failed(event)
+ end
+
+ subj.expects(:event_failed)
+
+ subj.null!
+ end
+
+ test 'should call aasm_event_failed if defined and transition failed for non-bang fire' do
+ subj = StateMachineSubject.new
+ def subj.aasm_event_failed(event)
+ end
+
+ subj.expects(:event_failed)
+
+ subj.null
+ end
+end
+
+class StateMachineStateActionsTest < ActiveModel::TestCase
+ test "calls enter when entering state" do
+ subj = StateMachineSubject.new
+ subj.expects(:enter)
+ subj.close
+ end
+
+ test "calls exit when exiting state" do
+ subj = StateMachineSubject.new
+ subj.expects(:exit)
+ subj.close
+ end
+end
+
+class StateMachineInheritanceTest < ActiveModel::TestCase
+ test "has the same states as its parent" do
+ assert_equal StateMachineSubject.state_machine.states, StateMachineSubjectSubclass.state_machine.states
+ end
+
+ test "has the same events as its parent" do
+ assert_equal StateMachineSubject.state_machine.events, StateMachineSubjectSubclass.state_machine.events
+ end
+end
+
+class StateMachineSubject
+ state_machine :chetan_patil, :initial => :sleeping do
+ state :sleeping
+ state :showering
+ state :working
+ state :dating
+
+ event :wakeup do
+ transitions :from => :sleeping, :to => [:showering, :working]
+ end
+
+ event :dress do
+ transitions :from => :sleeping, :to => :working, :on_transition => :wear_clothes
+ transitions :from => :showering, :to => [:working, :dating], :on_transition => Proc.new { |obj, *args| obj.wear_clothes(*args) }
+ end
+ end
+
+ def wear_clothes(shirt_color, trouser_type)
+ end
+end
+
+class StateMachineWithComplexTransitionsTest < ActiveModel::TestCase
+ def setup
+ @subj = StateMachineSubject.new
+ end
+
+ test 'transitions to specified next state (sleeping to showering)' do
+ @subj.wakeup! :showering
+
+ assert_equal :showering, @subj.current_state(:chetan_patil)
+ end
+
+ test 'transitions to specified next state (sleeping to working)' do
+ @subj.wakeup! :working
+
+ assert_equal :working, @subj.current_state(:chetan_patil)
+ end
+
+ test 'transitions to default (first or showering) state' do
+ @subj.wakeup!
+
+ assert_equal :showering, @subj.current_state(:chetan_patil)
+ end
+
+ test 'transitions to default state when on_transition invoked' do
+ @subj.dress!(nil, 'purple', 'dressy')
+
+ assert_equal :working, @subj.current_state(:chetan_patil)
+ end
+
+ test 'calls on_transition method with args' do
+ @subj.wakeup! :showering
+
+ @subj.expects(:wear_clothes).with('blue', 'jeans')
+ @subj.dress! :working, 'blue', 'jeans'
+ end
+
+ test 'calls on_transition proc' do
+ @subj.wakeup! :showering
+
+ @subj.expects(:wear_clothes).with('purple', 'slacks')
+ @subj.dress!(:dating, 'purple', 'slacks')
+ end
+end