« Playing with a Testing Library | Main | Complex and Rational are now built-in to 1.9 »

March 14, 2008

Source Code for that Testing Library

Ring the bells that still can ring
Forget your perfect offering
There is a crack in everything
That's how the light gets in.
  —Leonard Cohen

Yesterday, I posted on a trivial little testing library I hacked together. I've put the source online. Get the source through Rob's git repository (see below).

In the meantime, I discovered a problem with the idea of intercepting comparison operators, the technique used by the expect method. Ruby doesn't really have != and !~ methods. Instead, the parser maps (a != b) into !(a == b). This means that the ComparisonProxy cannot intercept calls to either of these. This is a problem because

   expect(1) != 1
actually passes, because it becomes !(expect(1) == 1), and the expect method is happy with that.

I'm betting there's a way around this...

Update: 14:26 CDT.

  • Rob Sanheim has set up a Git repository for the code. He says

    I've put this up on github to watch what forks or releases develop around it.

    
    git clone git://github.com/rsanheim/prag_dave_testing.git
    
  • Michael Neumann suggested a way around the negated == and =~ tests using source inspection:

    
     class ComparatorProxy
       def ==(obj)
         # try to get the source code position of the call
         # and see if it's a != or a ==
       end
     end
    

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/t/trackback/2226312/27094472

Listed below are links to weblogs that reference Source Code for that Testing Library:

Comments

expect(1 != 1) ?

Of course, now I look at your library and see- that's now how it's meant to be used at all.

I've put this up on github to watch what forks or releases develop around it.

git clone git://github.com/rsanheim/prag_dave_testing.git

Why not: expect { 1 == 1 }? Would also enable you to rescue Exceptions raised by the code.

Apeiros:

Having expect{ 1 == 1 } 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

If SCRIPT_LINES__ is a hash, it will hold all sources parsed after it was set. See lib/debug.rb.

Nobo-san:

I thought about SCRIPT_LINES__, but decided against it because I'd need to ensure that the testing library got control early. I was also nervous that with a large application I'd always be loading in a lot of code that I may never use. Reopening the source is a fairly small overhead for something that happens infrequently.


Dave

The library also has a problem if an individual test is continued on multiple lines. The report line that begins "the code was:" is incorrect. Correctly identifying the code for the test is an interesting problem.

I've forked this from rsanheims github and worked a little bit on it. I've patched the negation issue und started to write some tests and a run helper for testing itself.

For example:

require 'test_helper'

testing "negated comparison with !=" do

result = run { expect(1) != 1 }
expect(result) =~ /but\s1\s==\s1/

end

You can get it here:

git://github.com/mhennemeyer/prag_dave_testing.git

Matthias

A few more notes:

I had a long night hacking all the features together i would like
this framework to have.

While its still very experimental and not well tested I
can frankly say that it turned out as really nice.

(got it? git clone git://github.com/mhennemeyer/prag_dave_testing.git)


This are the features:

1. Upgraded transactional behavior:

testing "Transactional db testing" do
Model.destroy_all
testing "Create a model" do
Model.create
expect(Model.count) == 1
end
expect(Model.count) == 0
end

(This works only with sqlite3 and if the test db file
is named db/test.sqlite3)

2. Macro style testing block reuse:

testing "macro" do
@var = 1
testing "var should eql 1" do
expect(@var) == 1
end
# the testing block can be reused:
# 'expect_' + testing block name joined with underscores
expect_var_should_eql_1
end

This macro thing, together with the transactional behavior
lets you evaluate a testing block in different environments.
The environments will not be touched by the testing code:


testing "macros should behave transactional too" do
@var = 1
testing "change var to 5" do
@var = 5
end
expect_change_var_to_5
expect(@var) == 1
end


3. Rails Integration Testing:

integration_test do
testing "I can use the Integration::Session methods" do
post "/models", 'model' => {}
expect(@resonse.response_code)
end
end
What do you think?

Matthias

Post a comment

If you have a TypeKey or TypePad account, please Sign In

Now in Beta

  • Programming Ruby, 3rd Edition
    Third Edition, Covering Ruby 1.9, now in beta
My Photo

Site Search

  • Google Search

    The web
    PragDave

Pragmatic Stuff

Photos

  • www.flickr.com
    This is a Flickr badge showing public photos from pragdave tagged with pragdave_badge. Make your own badge here.