monicao
5/13/2014 - 9:40 PM

TDD Lecture Notes

TDD Lecture Notes

What is TDD?

  • write a test first
  • see it fail
  • write the implementation
  • see the test pass "the red green loop"

How much should you test?

NOTE: Some say: only write essential test initially. Add edge cases later.

History

  • started around 2003, XP (software dev methodology meant to accommodate changing customer requirements)
  • popular, but not as widely adopted as it may seem

Why do TDD?

Advantages:

  • better understanding of the problem
  • instant feedback when a change causes an error
  • eliminate bugs early (costs less)

Disadvantages:

  • "test induced design damage" - DHH
  • passing unit tests can give a false sense of security. need integration tests too. need to test how your classes interact with each other and with external things (libraries you use, databases, internet services)

RSpec

One of three major ruby testing frameworks.

  • RSpec
  • MiniTest
  • TestUnit
  • Mocha (not a full test framework, just for mocking... we'll talk about that later)

RSpec Setup

RSpec is a ruby gem. You can find the source code online here: https://github.com/rspec/rspec

If you are working with a pure ruby app, your folder structure might look like this:

lib/
   product.rb
spec/
   spec_helper.rb
   product_spec.rb

Coding

Code a small ruby app that keeps track of products and customer carts.

Introduce Guard

Starter code: git@github.com:lighthouse-labs/tdd_products_and_carts.git

Products

Have a name and a price_in_cents.

Carts

Are used to store products. Should be able to:

  • retrieve the list of products in a cart
  • add a product to the cart
  • check if the cart is empty
  • get the total dollar amount for the products in the cart
  • check if the customer is eligible for free shipping. this happens when the total cart value > $100
# spec/product_spec.rb
describe "Product" do
  describe "#initialize" do
    it "should create a product with a name and price"
    it "should raise an error if the price was not given"
  end
end
# spec/cart_spec.rb
describe "Cart" do
  describe "#initialize" do
    it "should create a cart"  # test without assertion
    it "should have no products in the cart"  # test exception
  end

  describe "products" do
    it "should return a list of products"  # attr_accessors should be tested b/c they are just methods
  end

  describe "#add_product" do
    it "should add a product to the cart" # use instance_variable_get(@products)
    it "should raise an ArgumentError if product is not a Product" 
    # it "should raise an InvalidProductError if product is not a Product"
  end

  describe "#empty?" do
    it "should return true if the cart is empty"
    it "should return false if there is an item"
  end

end

Ruby Floats and precision

Anyone wonder why we used price_in_cents to store the product price? Why not use a data type that looks more like a decimal?

You lose precision

1.0e9 + 1.0e-9
#=> 1000000000.0

Even with smaller numbers

0.2 - 0.05
#=> 0.15000000000000002

Even if statements don't act as you would expect

1.20 - 1.00 == 0.20
#=> false