module Clean #:nodoc: module Test #:nodoc: # A means of documenting the parts of your test code according # to the class "Given/When/Then" system. # This does no enforcement of any kind and is merely documentation to make # your tests readable. # # Example: # # Given { # @circle = Circle.new(10) # } # When { # @area = @circle.area # } # Then { # assert_equal 314,@area # } # # There are also two additional methods provided ,#the_test_runs and # #mocks_shouldve_been_called to assist with creating readable tests that use mocks. See those # methods for an example module GivenWhenThen # Public: Declare a step in your test, based on the following conventions: # # Given - This sets up conditions for the test # When - This executes the code under test # Then - This asserts that that the code under test worked correctly # And - Extend a Given/When/Then when using lambda/method form (see below) # But - Extend a Given/When/Then when using lambda/method form (see below) # # There are three forms for calling this method, in order of preference: # # block - in this form, you pass a block that contains the test code. This should be preferred as it # keeps your test code in your test # method - in this form, you pass a symbol that is the name of a method in your test class. This method # should set up or perform or assert whatever is needed. This can be useful to re-use test helper # methods in an expedient fashion. In this case, you can pass parameters by simply listing # them after the symbol. See the example. # lambda - in this form, you declare a method that returns a lambda and that is used as the # block for this step of the test. This is least desirable, as it requires methods to return # lambdas, which is an extra bit of indirection that adds noise. # # Parameters: # # existing_block - a callable object (e.g. a Proc) that will be called immediately # by this Given. If this is a Symbol, a method in the current scope will be converted into # a block and used. If nil, &block is expected to be passed # other_args - a list of arguments to be passed to the block. This is mostly useful when using method form. # block - a block given to this call that will be executed immediately # by this Given. If existing_block is non-nil, this is ignored # # Examples # # # block form # Given { # @foo = "bar" # } # # # method form # def assert_valid_person # assert @person.valid?,"Person invalid: #{@person.errors.full_messages}" # end # # Given { # @person = Person.new(:last_name => 'Copeland', :first_name => 'Dave') # } # Then :assert_valid_person # # # method form with arguments # def assert_invalid_person(error_field) # assert !@person.valid? # assert @person.errors[error_field].present? # end # # Given { # @person = Person.new(:last_name => 'Copeland') # } # Then :assert_invalid_person,:first_name # # # lambda form # def assert_valid_person # lambda { # assert @person.valid?,"Person invalid: #{@person.errors.full_messages}" # } # end # # Given { # @person = Person.new(:last_name => 'Copeland', :first_name => 'Dave') # } # Then assert_valid_person # # Returns the block that was executed def Given(existing_block=nil,*other_args,&block) if existing_block.nil? block.call(*other_args) block else if existing_block.kind_of?(Symbol) existing_block = method(existing_block) end existing_block.call(*other_args) existing_block end end # Public: Execute the code under test. Behavior identical to Given alias :When :Given # Public: Assert the results of the test. Behavior identical to Given alias :Then :Given # Public: Extend a Given/When/Then when using method or lambda form. Behavior identical to Given alias :And :Given # Public: Extend a Given/When/Then when using method or lambda form. Behavior identical to Given alias :But :Given # Public: Used to make clear the structure of tests using mocks. # This returns a no-op, and is intended to be used with a "When" # to delineate the creation of a mock in a Given, and the # expectations of a mock in a "Then" # # Example: # # Given { # @google = mock() # } # When the_test_runs # Then { # @google.expects(:search).with('foo').returns('bar') # } # Given { # @my_search = Search.new(@google) # } # When { # @result = @my_search.find('foo') # } # Then { # assert_equal 'Found bar',@result # } # And mocks_shouldve_been_called def the_test_runs lambda {} end # Public: Similar to #the_test_runs, this is used to make clear what # you are testing and what the assertions are. Since many Ruby mock # frameworks do not require an explicit "verify" step, you often have tests # that have no explicit asserts, the assertions being simply that the mocks were called # as expected. This step, which is a no-op, allows you to document that you are # expecting mocks to be called (rather than forgot to assert anything). # See the example in #mocks_are_called for usage. def mocks_shouldve_been_called lambda {} end end end end