-
Notifications
You must be signed in to change notification settings - Fork 16
Example Usage
Create a .doctest document, for example, “simple.doctest”, and begin documenting your application, like this:
Here is an example doctest file (say called simple.doctest):
This is an example test that succeeds
>> 1 + 2
=> 3
And here's a test that will fail
>> 1 + 2
=> 4
Test a some multiline statements
>> class Person
attr_accessor :name
end
>> Person
=> Person
>> p = Person.new
>> p.name = "Tom"
>> p.name
=> "Tom"
doctest: you split a file into separate named tests by adding a doctest: directive
>> 1 + 2
=> 4
Or, put your pastes in as comments within your ruby code, say, factorial.rb, like this:
# doctest: factorial should give correct results for 0 to 2
# >> factorial(0)
# => 1
# >> factorial(1)
# => 1
#
# comments describing the parameters can be included
# this is how it works with 2:
# >> factorial(2)
# => 2
def factorial(n)
if n == 0
1
else
n * factorial(n-1)
end
end
#
# doctest: should work for 3, too
#
# >> factorial(3)
# => 6
When the above code is run, i.e. with the command “rubydoctest factorial.rb”, it shows the following results:
=== Testing 'factorial.rb'...
OK | factorial should give correct results for 0 to 3
OK | should work for 3, too
6 comparisons | 2 doctests | 0 failures | 0 errors
You can do multiline statements like this, as long as the indentation level is greater than the >> start line (note that ‘end’ is at an unnatural indentation level):
# >> all_true = true
# >> 3.times do |t|
# all_true &&= (a[t] == b[t])
# end
# >> all_true
# => true
Here’s a more advanced usage example, in a Rails model, book.rb:
require File.join(File.dirname(__FILE__), "..", "rubydoctest_helper")
class Book < ActiveRecord::Base
# === Description
# Extension for sections and chapters collections
# e.g. book.sections.approved_only, book.chapters.dirty!
#
# === Tests
# doctest: Sample data should provide an example of a book with both approved
# and unapproved sections.
# >> v_a_books = Book.varied(:approved)
# >> v_a_books.size > 0
# => true
#
# doctest: Sample data should provide an example of a book with both dirty
# and non-dirty sections.
# >> v_d_books = Book.varied(:dirty)
# >> v_d_books.size > 0
# => true
module SectionExtension
# === Tests
# doctest: Book#sections.approved_only should return approved sections,
# including first-level sections, i.e "chapters".
# >> s = v_a_books.first.sections.approved_only
# >> s.size > 1
# => true
# >> s.any?{ |t| t.approved? }
# => true
# >> s.any?{ |t| !t.approved? }
# => false
def approved_only
self.select{ |s| s.approved? }
end
# === Tests
# doctest: Book#sections.unapproved_only should return unapproved sections,
# including first-level sections, i.e "chapters".
# >> s = v_a_books.first.sections.unapproved_only
# >> s.size > 1
# => true
# >> s.any?{ |t| t.approved? }
# => false
# >> s.any?{ |t| !t.approved? }
# => true
def unapproved_only
self.select{ |s| !s.approved? }
end
# === Tests
# doctest: Book#sections.dirty! should set the dirty flag for sections
# specific to the particular book it was called on.
# >> book = v_d_books.first
# >> (yes = book.sections.count(:conditions => ["dirty = ?", true])) > 0
# => true
# >> (no = book.sections.count(:conditions => ["dirty = ?", false])) > 0
# => true
# >> v_d_books.first.sections.dirty!
# >> book.sections.count(:conditions => ["dirty = ?", true])
# => yes + no
# >> book.sections.count(:conditions => ["dirty = ?", false])
# => 0
def dirty!
self.update_all ["dirty = ?", true]
end
end
has_many :sections, :extend => SectionExtension
# === Description
# Find books with a diverse set of sections with a certain property.
#
# === Examples
# @see SectionExtension module
def self.varied(field, min = 2)
find_by_sql \
"SELECT * FROM books WHERE id IN
(SELECT book_id FROM sections
GROUP BY book_id
HAVING COUNT(DISTINCT #{field}) >= #{min})"
end
end
See the Rails Usage page for more information about the rubydoctest_helper script mentioned above.
In each case, you run your tests using the rubydoctest command-line tool, e.g.:
$ rubydoctest doc/sample.doctest
$ rubydoctest factorial.rb
$ rubydoctest app/models/book.rb
Note also that you can use =begin and =end to suround the tests, ex: factorial.rb
def factorial(n)
if n == 0
1
else
n * factorial(n-1)
end
end
=begin
doctest: fact
>> factorial(0)
=> 1
=end
And that tests can be interspersed with comments, a la
# doctest: factial 0 is 1
# >> factorial(0)
# => 1
#
# These numbers grow much larger with a higher n:
#
# >> factorial(10)
# => 3628800
And since your test code and comments will appear in the rdocs, you’ve made instant documentation for parameters to your functions.
And all it cost was a copy and past from an irb session.