%# #% %# You can read this document in its full glory by #% %# opening ./doc/index.html in your favorite Web browser. #% %# #% %#---------------------------------------------------------------------------- %| section "Shell command" %#---------------------------------------------------------------------------- %|command! "dfect --help" do |node| %|text %= verbatim `ruby bin/#{node.title}` %#---------------------------------------------------------------------------- %| section "Ruby library" %#---------------------------------------------------------------------------- % def example_dfect_test *example_node_args, &block_containing_code_to_run % code_to_run = __block_content__(&block_containing_code_to_run).join % code_to_run.insert 0, "require 'dfect/auto'\n\n" %|example! *example_node_args When the following test is run: <% code :ruby do code_to_run end %> Dfect will output the following: <% text do IO.popen('ruby -Ilib 2>&1', 'w+') do |ruby| ruby.write code_to_run ruby.close_write ruby.read end end %> Begin by loading Dfect into your program: %|code :ruby require 'rubygems' # only necessary if you are using Ruby 1.8 require 'dfect' You now have access to the `Dfect` module, which provides methods that can be either mixed-in or called directly, according to your preference: %|code :ruby Dfect.D "hello" do # D() is a class method puts "world" end # the above is same as: include Dfect # mix-in the Dfect API D "hello" do # D() is an instance method puts "world" end %#-------------------------------------------------------------------------- %| section "Assertions" %#-------------------------------------------------------------------------- The following methods accept a block parameter and assert something about the result of executing that block. They also accept an optional message, which is shown in <%= xref "Failures", "failure reports" %> if they fail. See the <%= api_reference %> for more details and examples. %|table %|thead %|tr %|th Method %|th Description %|tbody %|tr %|td T %|td assert true (not `nil` and not `false`) %|tr %|td F %|td assert not true (`nil` or `false`) %|tr %|td E %|td assert that an execption is raised %|tr %|td C %|td assert that a symbol is thrown %#------------------------------------------------------------------------ %| section "Negation" %#------------------------------------------------------------------------ These methods are the *opposite* of <%= xref "Assertions", "normal assertions" %>. %|table %|thead %|tr %|th Method %|th Description %|tbody %|tr %|td T! %|td same as F %|tr %|td F! %|td same as T %|tr %|td E! %|td assert that an exception is *not* raised %|tr %|td C! %|td assert that a symbol is *not* thrown %#------------------------------------------------------------------------ %| section "Sampling" %#------------------------------------------------------------------------ These methods allow you to *check the outcome* of an assertion without recording a success or failure for that assertion in the execution report. %|table %|thead %|tr %|th Method %|th Description %|tbody %|tr %|td T? %|td returns `true` if T passes; `false` otherwise %|tr %|td F? %|td returns `true` if F passes; `false` otherwise %|tr %|td E? %|td returns `true` if E passes; `false` otherwise %|tr %|td C? %|td returns `true` if C passes; `false` otherwise %#------------------------------------------------------------------------ %| section "Failures" %#------------------------------------------------------------------------ When an assertion fails, details about the failure will be shown: - fail: block must yield true (!nil && !false) code: |- [12..22] in test/simple.rb 12 13 D "with more nested tests" do 14 x = 5 15 16 T { x > 2 } # passes => 17 F { x > 2 } # fails 18 E { x.hello } # passes 19 end 20 end 21 22 # equivalent of before(:each) or setup() vars: x: 5 y: 83 call: - test/simple.rb:17 - test/simple.rb:3 You will then be placed into a debugger to investigate the failure if the `:debug` option is enabled in the `Dfect.options` hash. Details about all assertion failures and a trace of all tests executed are stored by Dfect and provided by the `Dfect.report()` method. %#------------------------------------------------------------------------ %| section "Emulation" %#------------------------------------------------------------------------ Dfect provides emulation layers for several popular testing libraries: * dfect/unit --- Test::Unit * dfect/mini --- Minitest * dfect/spec --- RSpec Simply `require()` one of these emulation layers into your test suite and you can write your tests using the familiar syntax of that testing library. See [their source code](<%= source_code_url %>/tree/master/lib/dfect/) for more details. %#-------------------------------------------------------------------------- %| section "Tests" %#-------------------------------------------------------------------------- The `D()` method defines a new Dfect **test**, which is analagous to the concept of **test case** in xUnit or **describe** in rSpec. A test may contain nested tests. %|code :ruby D "outer test" do # assertions and logic here D "inner test" do # more assertions and logic here end end %#------------------------------------------------------------------------ %| section "Execution" %#------------------------------------------------------------------------ Tests are executed in depth-first order. You can configure the test execution process using: %|code :ruby Dfect.options = your_options_hash You can execute all tests defined thus far using: %|code :ruby Dfect.run You can stop the execution at any time using: %|code :ruby Dfect.stop You can view the results of execution using: %|code :ruby puts Dfect.report.to_yaml See the <%= api_reference %> for details and examples. %#---------------------------------------------------------------------- %| paragraph "Automatic test execution" %#---------------------------------------------------------------------- To mix-in the `Dfect` module into your program and execute all tests defined by your program before it terminates, simply add the following line at the top of your program: %|code :ruby require 'dfect/auto' %#---------------------------------------------------------------------- %| section "Hooks" %#---------------------------------------------------------------------- The `D()` method provides several entry points (hooks) into the test execution process: %|code :ruby D "outer test" do D .< { puts "before each nested test" } D .> { puts "after each nested test" } D .<< { puts "before all nested tests" } D .>> { puts "after all nested tests" } D "inner test" do # assertions and logic here end end A hook method may be called multiple times. Each call registers additional logic to execute during the hook: %|code :ruby D .< { puts "do something" } D .< { puts "do something more!" } %#---------------------------------------------------------------------- %| section "Logging" %#---------------------------------------------------------------------- The `L()` method lets you insert log messages, composed of arbitrary Ruby objects, into the test execution report. %|example_dfect_test "Logging information in the execution report" D 'Wizard' do L 'Preparing spell to defeat mortal foes...' end D 'Magician' do L 'Preparing rabbits to pull from hat...', rand(15) end D 'Calculator' do L Math::PI, [1, 2, 3, ['a', 'b', 'c']], {:foo => 'bar!'} end %#------------------------------------------------------------------------ %| section "Sharing" %#------------------------------------------------------------------------ The `S()` method is a mechanism for sharing code. When called with a block, it shares the given block (under a given identifier) for injection into other tests. When called without a block, it injects a previously shared block (under a given identifier) into the environment where it is called. The `S!()` method is a combination of the two uses of the `S()` method: it lets you simultaneously share a block of code while injecting it into the environment where that method is called. The `S?()` method simply checks whether any code has been shared under a given identifier. %|example_dfect_test "Sharing code between tests" S :knowledge do L 'Knowledge is power!' end D 'Healer' do S :knowledge end D 'Warrior' do S! :strength do L 'Strength is power!' end end D 'Wizard' do S :knowledge S :strength end D 'King' do T { S? :knowledge } T { S? :strength } F { S? :power } L 'Power is power!' end %#------------------------------------------------------------------------ %| section "Insulation" %#------------------------------------------------------------------------ The `D!()` method defines a new test that is explicitly insulated from the tests that contain it and also from the top-level Ruby environment. Root-level calls to the `D()` method are insulated by default. Inside an insulated test, you are free to: * mix-in any modules your test logic needs * define your own constants, methods, and classes %|example_dfect_test "Insulated and uninsulated tests" D "a root-level test" do @outside = 1 T { defined? @outside } T { @outside == 1 } D "an inner, non-insulated test" do T { defined? @outside } T { @outside == 1 } end D! "an inner, insulated test" do F { defined? @outside } F { @outside == 1 } @inside = 2 T { defined? @inside } T { @inside == 2 } end F { defined? @inside } F { @inside == 2 } end