[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

The unit test that won't.

Phillip Gawlowski

4/11/2007 5:25:00 AM

Aspiring to be a good programmer, I'm using Test::Unit for ClothRed,
writing the test before I write the code, even.

Which is all well and good, but I have a test, that produces an error
*while it is executed* and *not* in the error report:

test_textformatting(TestClothRedFormatting):
TypeError: can't convert nil into String
../test/../lib/clothred.rb:22:in `gsub!'
../test/../lib/clothred.rb:22:in `to_textile'
../test/../lib/clothred.rb:21:in `collect!'
../test/../lib/clothred.rb:21:in `to_textile'
../test/test_formatting.rb:43:in `test_textformatting'
../test/test_formatting.rb:41:in `each'
../test/test_formatting.rb:41:in `test_textformatting'

2 tests, 1 assertions, 0 failures, 1 errors

My tests look like this:

#Works:
def test_tags
assert_equal("**bold**", ClothRed.new("<b>bold</b>").to_textile)
end

#Doesn't work:
def test_textformatting
FORMATTING_STRINGS.each do |html, textile|
test_html = ClothRed.new(html)
test_html.to_textile
assert_equal(textile,test_html)
end
end

The Array is as follows:

FORMATTING_STRINGS = [
["<b>bold</b>","**bold**"], ["<strong>strong</strong>", "*strong*"],
["<em>emphasized</em>", "_emphasized_"],
["<i>italics</i>", "__italics__"],
["<cite>citation</cite>", "??citation??"],
["<code>ClothRed#to_textile</code>", "@ClothRed#to_textile@"],
["<del>delete</del>", "-delete-"],
["<ins>underline</ins>", "+underline+"],
["<sup>superscript</sup>","^superscript^"],
["<sub>subscript</sub>","~subscript~"]
]


An improvised test run produces this:

c:\test.rb
**bold**
_emphasized_
__italics__

c:\cat test.rb
# test.rb
# 11. April 2007
#

require 'clothred'



TEST = '<b>bold</b>
<em>emphasized</em>
<i>italics</i>'

test = ClothRed.new(TEST)

puts test.to_textile


My Ruby version:
c:\ruby -v
ruby 1.8.5 (2006-12-25 patchlevel 12) [i386-mswin32]

The output of the test suggests, that I'm doing something wrong in my
test, that my test is buggy, and not my code.

Can somebody enlighten me?

--
Phillip "CynicalRyan" Gawlowski
http://cynicalryan....

Rule of Open-Source Programming #6:

The user is always right unless proven otherwise by the developer.


4 Answers

Brian Candler

4/11/2007 5:50:00 AM

0

On Wed, Apr 11, 2007 at 02:24:37PM +0900, Phillip Gawlowski wrote:
> def test_textformatting
> FORMATTING_STRINGS.each do |html, textile|
> test_html = ClothRed.new(html)
> test_html.to_textile
> assert_equal(textile,test_html)

Hmm, it looks like test_html is not a string here, but some other sort of
object, so did you mean

assert_equal(textfile, test_html.to_s) ?

or else

result = test_html.to_textile
assert_equal(textile, result) ?

It depends whether your 'to_textile' method really changes the internal
state of your ClothRed object, or whether its return value is the thing
you're interested in checking.

B.

Phillip Gawlowski

4/11/2007 6:24:00 AM

0

Daniel N wrote:
> On 4/11/07, Phillip Gawlowski <cmdjackryan@googlemail.com> wrote:
>>
>>
>>
>> My tests look like this:
>>
>> #Works:
>> def test_tags
>> assert_equal("**bold**", ClothRed.new("<b>bold</b>").to_textile)
>> end
>>
>> #Doesn't work:
>> def test_textformatting
>> FORMATTING_STRINGS.each do |html, textile|
>> test_html = ClothRed.new(html)
>> test_html.to_textile
>> assert_equal(textile,test_html)
>> end
>> end
>
>
> As Brian says, I'm not really sure what test_html.to_textile leaves
> test_html as but why not go back to what works for you. It seems
> simpler to
> me also.
>
> def test_textformatting
> FORMATTING_STRINGS.each do |html, textile|
> assert_equal(textile, ClothRed.new(html).to_textile )
> end
> end
>
> also a failing message wouldn't go astray. Something like
>
> def test_textformatting
> FORMATTING_STRINGS.each do |html, textile|
> transformed = ClothRed.new(html).to_textile
> assert_equal(textile, transformed ), "\"#{html}\" should have
> transformed to \"#{textile}\¨ but was \"#{transformed}\""
> end
> end
>
> just my 0.02
>

Thanks for the input guys, looks like the error *was* in my code after all.
Here's the why:

ClothRed#to_textile used Array#collect! to iterate over the string that
was to be transformed, which let the first test complete successfully as
it was only testing for *one* condition. As soon as I change #collect!
to #each, the code behaved as the test expected. Although why this
happens, I'm not sure (I guess the receiver of the block is the "count"
for the block, and not the elements in the Array).

Which leads to the discovery of another bug now, which is in my regex.

--
Phillip "CynicalRyan" Gawlowski
http://cynicalryan....

Eek! That was supposed to be My Special Law, _MY_ special law, I tell
you!

T/


Brian Candler

4/11/2007 7:34:00 AM

0

On Wed, Apr 11, 2007 at 03:23:52PM +0900, Phillip Gawlowski wrote:
> ClothRed#to_textile used Array#collect! to iterate over the string that
> was to be transformed, which let the first test complete successfully as
> it was only testing for *one* condition. As soon as I change #collect!
> to #each, the code behaved as the test expected. Although why this
> happens, I'm not sure (I guess the receiver of the block is the "count"
> for the block, and not the elements in the Array).

I don't understand what you've written above - you might want to paste an
example. For both Array#each and Array#collect!, the values passed to the
block are the elements of the array. The difference is in what happens to
the value returned by the block; #each ignores it, #collect! replaces the
original array element with it.

As a separate point though: if to_textile changes the state of your ClothRed
object, you might want to consider calling it something else.

Normally, a to_foo method returns an object of type foo, and does not change
the state of the receiver. Compare Object#to_yaml, Method#to_proc,
Object#to_enum and so on.

Personally I would be surprised to find a Ruby library with a "to_textile"
method, where the main purpose of the function was to change the state of
the receiver, and _not_ to return a textile object.

Regards,

Brian.

Phillip Gawlowski

4/11/2007 8:23:00 AM

0

Brian Candler wrote:

> I don't understand what you've written above - you might want to paste an
> example. For both Array#each and Array#collect!, the values passed to the
> block are the elements of the array. The difference is in what happens to
> the value returned by the block; #each ignores it, #collect! replaces the
> original array element with it.

Ah, that cleared up *my* confusion. I wanted #each in the first place,
but made mistakes in writing my code.

Well, the learning never stops.

> As a separate point though: if to_textile changes the state of your ClothRed
> object, you might want to consider calling it something else.

I have changed that behavior. #to_textile is non-destructive (at least
it should be, I have to add a test for that).

> Personally I would be surprised to find a Ruby library with a "to_textile"
> method, where the main purpose of the function was to change the state of
> the receiver, and _not_ to return a textile object.

Yes, I'd expect that from #to-textile!, too, which was my intention in
the first place.

--
Phillip "CynicalRyan" Gawlowski
http://cynicalryan....

Rule of Open-Source Programming #48:

The number of items on a project's to-do list always grows or remains
constant.