I’m at RailsConf Europe here in Berlin, and now attending the full-day session “Ruby (and Rails) Testing Techniques: Charity Tutorial by Marcel Molina and Chad Fowler.
Below are the live notes, I wrote with Mads Buus (we wrote the notes collaboratively with Google Docs, direct link).
- Verifying your expectations.
- Guru reads the output” -testing (just printing stuff out to verify something)
- Testing is better: declare your expectations.
- Real value: Analysis, design process. Bonus: verification.
- If something is too hard to write, you’re probably doing it wrong (design is wrong)
- Red, green, refactoring. Write a test that fail, the implement until green.
- Red/green testing: Write code to make testing fail… red. Then write just enough code to make test pass.
- Marcel’s loops coding/testing is 1-5 minutes. Possible to work with 20 second loops
- No ‘Code smells’, no comments. ‘method_missing’ needs documentation
Your code should be so simple that you shouldnt put comments in your code. If it just says “test_foo” [new team members] have to do more brain processing.
Nick: think of my self as a spec writer more than a programmer
* refactor your tests before
flunk “not implemented” is cool because i can see that it’s
RSpec makes “not implemented” yellow so it doesn’t mix up with the red
Marcel: Eventually we re all going to be small talk programmers. Ruby is the entry drug
class PokerException < Exception
doesnt need right now. always add later. Removed
Chad: i really work in small increments
Marcel: at the beginning i did “existing? tests”
…and within 15 minutes that test becomes so non valuable.
Chad: I challenge you to write long method names … at least for a day or two
When you follow that style, your code will be cleaner and healthier
Write flunking test to identify an assumptions
flunk ‘we probably want to create a validation test case for this’
Chad: Have you run your other test recently?
Chad: Id like to have only one test failing at a time
Mads: Instead of fixing the design, we wirte more tests. Are we thinking too much about test than the code?
Chad: now, were running into friction. and frictions tell us tu stop and think about the design
— break —
(my comment: the discussions her usually get into details with “business-logic”)
test helper function
card_with(options) is subverting the benefit of the tests as long as Marcel uses that in the test file only.
Private methods in Test::Unit
doesnt impact Test::Unit
but the fact is that the reader of the code can ignore them below the private
Chad: TDD enables you to delay difficult decisions.. … and you keep delaying them, and it ends up that you never have to take the difficult decisions
class << self
M: Visually the latter is better. Easier to grasp overview of the class. Also when you add private methods later, there are more sections of your class
AgileTalk “just print all names of your test methods” (not found by me on google)
“Test everything that could possibly break” quote by kent beck.
That domain spsecific understanding grows over time. So if something weird with card number 11 happens, then you should probably add a test case for number 11.
“if it’s strip poker I can see why we implement base class”
$: = LOAD_PATH
$: .unshift File.dirname(__FILE__)
Adding current directory onto our loadpath
DR. Jekyll and Mr hyde
The good Dr. Jekyll writes a test, then laugh at Mr Hyde (the lazy programmer) and force him to implement the smallest amount of code to make it pass
Incremental refactoring: Even if you are able to see more steps ahead, you should do Incremental refactoring and test on the way.
Moving from low-level to high-level
Metrics for measuring test quality
rake test:ratio (marcels own)
Code to Test Ratio: 1:1.28
issue: sometimes reports false negatives (example lines not covered “end..end..end”)
c0, c1, c2 coverage
Line number counting
code to Test ratio and Rcov used together is very good indicators.
Heckle can go into those examaples with more loops on the same line
if foo && bar && baz
Here Hecle will go in and modify bar until test breaks
Now into the highl-level
(Jim Weirich (co?)authored it and we tend to use libraries he wrote)
@game = flexmock(‘Game’)
@dealer = flexmock(‘Dealer’)
@player1 = flexmock(‘Player’)
@player2 = flexmock(‘Player’)
Chad (again): “it would be interesting to run just what you have and see what it does”
@game = flexmock(‘Game’)
@game = flexmock(Game.new)
mocks if methods are not implemented.
@game = flexmock(Game).new_instances
pain to deal with, and not so explicit
it makes sense to mock up and never hit the db
class Person < ActiveRecord::Base
####test file below:
#… valid_person definde helper method
assert_equal admin_for_company, Person.admin
#always methods parametrized to be overridden
Marcel: For 2 years, fixtures made me angry with rails
Chad: We only hate it because its not as good as the rest of Rails, but it’s better than what we had before
Test::Unit leads to one test per method in your code
Test usually takes longer.
b vs t Behaviours versus testing: So
=> good Test Driven Development with the word “test” removed from it
Is your name Dan, by any chance? Did you coin the term BDD, by any chance?
rspec is a specification framework
tools more implemented and more into textmate
not passing a block is an unimplemented spec
Its developed way more actively than Test::Unit and it’s also the tooling around it
RSpec generators (general opinion) they are probably too long
=== Jesper’s notes below:===
Windows shortcuts for E-texteditor
- CTRL+R run test file we’re working in.
- CTRL+Shift+R run test in focus
- deft + tab “def test_ … end”
Idea for “deft” shortcut: replace all spaces as-you-type with underscores