Playing with a Testing Library
-
I'd like to be able to express my unit tests fairly naturally, using the conditional operators built into the language. So, for example, I'd want to write:
expect(factorial(5)) == 120 expect(factorial(10)) > 10000 -
I'd like the error messages to show both the code that caused the error and the values that caused the error. So, for example, I'd want the following (incorrect) test
expect(factorial(6)) == 600to output something like
/Users/dave/tmp/tmc/blog_tests.rb:16 the code was: expect(factorial(6)) == 600, but 720 != 600and
expect(1) > 2should say
/Users/dave/Play/tmc/blog_tests.rb:11 the code was: expect(1) > 2, but 1 <= 2(Note how the expression showing the actual values negates the comparison operator to make it easier to read.)
-
I annotate my code with comments, so I'd like to be able to annotate my
tests the same way.
expect(factorial(6)) == 600 # Deliberate bad testshould produce something like
/Users/dave/tmp/tmc/blog_tests.rb:17 Deliberate bad test the code was: expect(factorial(6)) == 600, but 720 != 600Sometimes I write longer comments.
# The factorial of 6 is a special case, # because of the labor laws in Las Vegas expect(factorial(6)) == 600So the resulting errors are longer, too.
/Users/dave/Play/tmc/blog_tests.rb:21 The factorial of 6 is a special case, because of the labor laws in Las Vegas the code was: expect(factorial(6)) == 600, but 720 != 600 -
I like to be able to group my tests.
testing("positive factorials") do expect(factorial(1)) == 1 expect(factorial(2)) == 2 expect(factorial(5)) == 120 end testing("factorial of zero") do expect(factorial(0)) == 1 end testing("negative factorials") do expect(factorial(-1)) == 1 expect(factorial(-5)) == 1 end -
I like the description of the group to appear along with any individual test annotation if a test fails.
will producetesting("factorial of zero") do # this test is deliberately wrong expect(factorial(0)) == 0 end/Users/dave/Play/tmc/blog_tests.rb:31--while testing factorial of zero this test is deliberately wrong the code was: expect(factorial(0)) == 0, but 1 != 0 -
I like to have the flexibility to set up the environment for a group of tests. I also like to have the idea of a global environment which doesn't get messed up by the running of tests (so that subsequent tests can run in that environment. I don't see why I should have to package things into methods with magic names to have that happen. Instead, why not just have transactional instance variables? That way, I can use regular methods to set up the state for a test.
@order = Order.new("Dave Thomas", "Ruby Book") testing("normal case") do expect(@order.valid?) == true end testing("missing name in order") do @order.name = nil expect(@order.valid?) == false expect(@order.error) == "missing name" end # Check that order is reset to valid state here expect(@order.valid?) == trueSo, in the preceding case, the second
testingblock changed the@orderobject. However, once the block terminated, the object was restored to its initial (valid) state.





Nicolás:
It does indeed support comparisons other than '==', and adding custom matchers would be trivial.
Dave
Posted by: Dave Thomas | March 14, 2008 at 07:31 AM
Release early, release often.
Posted by: Christian Romney | March 14, 2008 at 05:14 PM
Gregor:
Having expect{ 1 == 2} wouldn't give me access to the individual values when reporting errors--I can only change the meaning of == after the code being tested has run.
Dave
Posted by: Dave Thomas | March 15, 2008 at 08:22 AM
I love the idea of using code comments for your assertion messages. This is something I've always wanted as it makes for much cleaner code while providing useful output. I also like the grouping concept.
I'd love to know as soon as this is available.
Posted by: Eric Broyles | March 24, 2008 at 09:53 AM