Computer Science and Engineering The Ohio State University
1. If buggy code never gets executed, is it still wrong?
2. Evaluate:
assert_equal 129.95 * 100, 12995
Copyright By PowCoder代写 加微信 powcoder
Testing Frameworks
(MiniTest: Assert & Spec)
Computer Science and Engineering College of Engineering The Ohio State University
MiniTest and RSpec
MiniTest (replaces older Test::Unit) Comes built-in
Looks like JUnit (mapped to Ruby syntax) Well-named!
Installed as a library (i.e. a “gem”)
Looks different from JUnit (and even Ruby!) Most unfortunate name!
RSpec view is that test cases define
expected behavior—they are the spec!
What is wrong with that view?
Computer Science and Engineering The Ohio State University
Many popular testing libraries for MiniTest Tests
Computer Science and Engineering The Ohio State University
Require runner and UUT
require ‘minitest/autorun’ #the test runner require ‘card’ #the UUT
Test fixture: subclass of MiniTest::Test class TestCard < MiniTest::Test
Test case: a method in the fixture Method name must begin with test_
def test_identifies_set ... end
Contains assertion(s) exercising a single piece of code / behavior / functionality
Should be small (i.e. test one thing)
Should be independent (i.e. of other tests)
Test Suite: a collection of fixtures
Example: test_card.rb
Computer Science and Engineering The Ohio State University
require 'minitest/autorun'
require 'card' # assume card.rb on load path
class TestCard < MiniTest::Test
def test_has_number
assert_respond_to Card.new, :number
def test_remembers_number
@card = Card.new 1, "oval", "open", "red"
assert_equal 1, @card.number
Execution Model
instance of
instance of
has_number()
remembers()
Computer Science and Engineering The Ohio State University
has_number()
remembers()
Execution Model: Implications
Computer Science and Engineering The Ohio State University
Separate instances of test class created One instance / test case
Test cases don't have side effects Passing/failing one test does not affect others
Can not rely on order of tests Randomized order of execution
Controllable with --seed command-line option Also controllable by invoking, in test fixture:
i_suck_and_my_tests_are_order_dependent!
Fixture: common set-up to all test cases Field(s) for instance(s) of class being tested
Factor initialization code into its own method This method must be called setup
Good Practice: setup
Computer Science and Engineering The Ohio State University
Initialize a fixture with a setup method
(rather than initialize method)
If the code being tested throws an exception during the setup, the output is much more meaningful
Symmetry with teardown method for cleaning up after a test case
Example: test_card.rb
Computer Science and Engineering The Ohio State University
require 'minitest/autorun'
require 'card' #assume card.rb is on load path
class TestCard < Minitest::Test
@card = Card.new 1, "oval", "open", "red"
def test_has_number
assert_respond_to @card, :number
def test_remembers_number
assert_equal 1, @card.number
Execution Model
Computer Science and Engineering The Ohio State University
instance of
has_number()
remembers()
instance of
has_number()
remembers()
MiniTest Assertion Methods
Computer Science and Engineering The Ohio State University
Most have two versions: assert & refute Example: assert_nil, refute_nil
No need for negation (use refute instead)
Most take an optional message
assert_empty Library.new,
"A new library contains no books"
Message appears when assertion fails Specials:
pass/flunk – always passes/fails skip – skips the rest of the test case
Performance benchmarking also available
Asserting Equality
Assert two objects are == equal assert_equal expected, actual
Compares object values (i.e. == in Ruby)
Failure produces useful output
TestCard#test_total_number_of_cards
Expected: 81
Actual: 27
Compare with assert exp == actual TestCard#test_shuffle_is_permutation Failed assertion, no message given
Assert two objects are aliased
assert_same @table.north, @players.first
Compares reference values (i.e. .equal?)
Computer Science and Engineering The Ohio State University
Good Practice: Comparing Floats
Computer Science and Engineering The Ohio State University
Never compare floating point numbers
directly for equality
assert_equal 1.456, calculated,
"Low-density experiment"
Numeric instabilities make exact equality problematic for floats
Better: Equality with tolerance
assert_in_delta Math::PI, (22.0 / 7.0),
0.01, "Archimedes algorithm"
assert_in_epsilon Math::PI, (22.0 / 7.0),
0.1, "Archimedes algorithm"
Delta for absolute error, epsilon for relative error
Common Assertions
Checks the result of #nil? refute_nil @library.manager
# ie refute @library.manager.nil?
Is empty: assert_empty (refute_emp)
Checks the result of #empty? assert_empty Library.new
# ie assert Library.new.empty?
Computer Science and Engineering The Ohio State University
Boolean condition: assert (refute) assert @books.all {|b| b.available?}
Is nil: assert_nil (refute _nil)
More Assertions
String matches a regular expression
assert_match /CSE.*/, @course.name
Collection includes a particular item
assert_includes @library, @book
Object is of a particular type
assert_instance_of String, @book.title
Object has a method
assert_respond_to @student, :alarm
Block raises an exception
assert_raises ZeroDivisionError do
@library.average_book_cost
Computer Science and Engineering The Ohio State University
Test Suite
Gather fixtures together in one place
Computer Science and Engineering The Ohio State University
Good Practice: Organization
Computer Science and Engineering The Ohio State University
Keep tests in the same project as the
They are part of the build, the repo, etc. Helps to keep tests current
Separate tests and implementation
/set/lib – contains card.rb (implementation) /set/tests – contains test_card.rb (tests)
Name test classes consistently TestCard tests Card
Test fixture is a Ruby program
[setapp] $ ruby tests/test_card.rb
Test needs to be able to find UUT (require)
Add location of UUT to load path
[setapp] $ ruby –I lib tests/test_card.rb
Alternative Syntax
Problem: Cumbersome method names
test_shuffle_changes_deck_configuration
Solution: exploit Ruby language flexibility in API of testing library
Methods are available that change the syntax and structure of test cases "Domain-specific language" for testing
Result: MiniTest::Spec Notation inspired by RSpec
Computer Science and Engineering The Ohio State University
Writing MiniTest::Spec Tests
Computer Science and Engineering The Ohio State University
Require spec library (+ runner + UUT)
require 'minitest/spec’
Test fixture (an “example group”) is a
describe block describe Card do ... end
Can be nested, and identified by string The block contains examples
Test case (an “example”) is an it block it 'identifies a set' ... end
Contains expectation(s) on a single piece of code / behavior / functionality
Expectations are methods on objects
@card.number.must_equal 1
Example: test_card.rb
Computer Science and Engineering The Ohio State University
require 'minitest/spec'
require 'minitest/autorun'
require 'card' #assume card.rb is on load path
describe Card, "game of set" do
it "has a number" do
Card.new.must_respond_to :number
it "remembers its original number" do
@card = Card.new 1, "oval", "open", "red"
@card.number.must_equal 1
Expectations vs. Assertions
Computer Science and Engineering The Ohio State University
Similarity: Positive and negative form
must_be_empty # like assert_empty wont_be_empty # like refute_empty
Difference: Argument order
assert_equal expected, actual
actual.must_equal expected
Difference: No string argument
Meaningful output comes from group
name and example name
Card::game of set#test_0001_has a number
[test_card.rb:14]:
Expected #
respond to #number.
Obj.must_ + …
Computer Science and Engineering The Ohio State University
General expectation: Must be
x.must_be :<, 10
Many other flavors of expectation...
x.must_equal y
x.must_be_same_as y
@library.manager.must_be_nil
@shelf.must_be_empty
@library.must_include @book
PI.must_be_within_delta (22.0 / 7.0), .01
@book.title.must_be_instance_of String
@course.name.must_match /CSE.*/
@student.must_respond_to :alarm
@library.average_book_cost
}.must_raise ZeroDivisionError
Setup/Teardown
Methods before, after Arguments :each or :all
describe Student do
before :each do
@buck_id = BuckID.new "4328429"
@s = Student.new buck_id
it 'should come to class' do ... end
Computer Science and Engineering The Ohio State University
Let: Lazy Initialization
Computer Science and Engineering The Ohio State University
describe Student do
# both defines a method (student) # and memoizes its return value! let(:student) { Student.new 1234 }
describe "sleep deprivation"
it "misses class" do
student.awake?.must_equal false
RSpec: Set up and Use
Computer Science and Engineering The Ohio State University
Install the rspec gem locally
[~] $ gem install rspec
Set up your program to use rspec
[myapp] $ rspec –-init
Init creates several things in myapp/
spec/ # put tests (foo_spec.rb) here spec/spec_helper.rb # configures paths .rspec # default command-line args
[myapp] $ rspec spec/foo_spec.rb
Example Groups and Examples
require_relative '../student'
describe Student do
it "can drop a class" do
Computer Science and Engineering The Ohio State University
#example group
context "when attending lecture" do
before :each do ... end
it "stays awake during lecture" do
it "stores info until exam" do
RSpec Expectations
Examples of condition ==, equal,
factor.should equal 34
be_true, be_false, be_nil, be_empty
list.emtpy?.should be_true
have(n).items, have_at_most(n).items
include(item)
list.should include(name)
match(regex) respond_to(method_name)
New form: expect().to (or not_to)
expect(a_result).to eq "OSU"
Computer Science and Engineering The Ohio State University
Verb is "should" (or "should_not")
target.should condition #notice space
Computer Science and Engineering The Ohio State University
Top-down: testing a class that uses A, B, C
Problem: We don't have A, B, C
Want quick approximations of A, B, C
Behave in certain way, returning canned answers
Solution: Stub method
Takes a hash of method names & return values
Returns an object with those methods
stub_printer = stub :available? => true,
:render => nil
Another form adds (or changes) a
method/return value of an existing object long_str = ‘something’
long_str.stub (:length).and_return(1000000)
Stubs passively allow the test to go through
Mocks monitor how they are used (and will fail if they aren’t used right)
it ‘should know how to print itself’ do
mock_printer = mock(‘Printer’)
mock_printer.should_receive
(:available?).and_return(true)
mock_printer.should_receive
(:render).exactly(3).times
@doc.print (mock_printer).should
== ‘Done’ end
Computer Science and Engineering The Ohio State University
Computer Science and Engineering The Ohio State University
Test fixture: class extending Minitest::Test Test case: method named test_
Execution model: multiple instances Independence of test cases
MiniTest::Spec
Examples and expectations String descriptions
Stubs and mocks
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com