Clearer errors in 1.9's minitest

Hello!

I’ve been getting back into Ruby, and one of the major changes I’ve
made is to switch to 1.9 and to strictly use tests. I’m using the
minitest[1] in 1.9 (via rvm[2])

It’s nice, and I’m pleased at what I’ve been able to accomplish with
its help.

However, it’s been long enough that one issue has pissed me off
to no end and I need some advice on it. I’m not sure how to describe
what I’m looking for concisely enough to search for it effectively, so
I thought I’d sign up and ask.

When an error is caught, its output is not as helpful as I wish it to
be.

Example script:


require ‘minitest/autorun’

class Test_Markup < MiniTest::Unit::TestCase

def test()
assert_equal(
( 'asdfghjkl asdfghjkl asdfghjkl asdfghjkl asdfghjkl ’ ),
( 'qwertyuiop qwertyuiop qwertyuiop qwertyuiop qwertyuiop ’ ),
)
end

end

Example output:


Loaded suite /foo/bar/baz.rb
Started
F
Finished in 0.000440 seconds.

  1. Failure:
    test(Test_Markup)
    [/foo/bar/baz.rb:7]:
    Expected "asdfghjkl asdfghjkl asdfghjkl asdfghjkl asdfghjkl ", not
    "qwertyuiop qwertyuiop qwertyuiop qwertyuiop qwertyuiop ".

1 tests, 1 assertions, 1 failures, 0 errors, 0 skips

Test run options: --seed 48126

The “expected/not” text is not nearly as helpful to me as it
could/should be. It forces me to

  • copy/paste it to a text file
  • shove the text around to “line it up”
  • comb through it character-by-character for differences
  • slowly go insane(r)

What I instead want is to have a coloured side-by-side comparison
similar to a decent diff.

Is this possible within minitest as it stands currently? Has anyone
else done this already, perhaps with other libraries/tools?

How challenging would this be to implement? If there were some way for
me to “get at” that text, I could use existing and very mature external
tools to do exactly what I want. e.g. if I were given one big array
with sub-arrays, within which is all the error information… then I
could do some real magic.

I’d really rather not use an alternative to minitest, mostly because
the syntax used in them makes me want to scoop my brain out with a
teaspoon.

Point me to websites, documentation or source code. Any and all help
is appreciated.


[1] http://bfts.rubyforge.org/minitest/
[2] http://rvm.beginrescueend.com/rvm/

http://spiralofhope.com

Wall of text hits you for 99,999 hp.
You die!

On Mar 25, 2011, at 21:13 , spiralofhope wrote:

to no end and I need some advice on it. I’m not sure how to describe

class Test_Markup < MiniTest::Unit::TestCase

def test()
assert_equal(
( 'asdfghjkl asdfghjkl asdfghjkl asdfghjkl asdfghjkl ’ ),
( 'qwertyuiop qwertyuiop qwertyuiop qwertyuiop qwertyuiop ’ ),
)
end

end

You don’t actually write your code that way, do you?

teaspoon.

Point me to websites, documentation or source code. Any and all help
is appreciated.

You already have the source code. Have you read it? It is called
minitest for a reason. Dig in.

test_example(TestMarkup) [./x.rb:8]:
Expected "asdfghjkl asdfghjkl asdfghjkl asdfghjkl asdfghjkl ", not "qwertyuiop
qwertyuiop qwertyuiop qwertyuiop qwertyuiop ".

1 tests, 1 assertions, 1 failures, 0 errors, 0 skips

versus:

On Sun, 27 Mar 2011 05:12:51 +0900
Ryan D. [email protected] wrote:

You don’t actually write your code that way, do you?

I’m assuming you’re commenting on my general style. Moved to another
thread. CCed you.

% sudo gem install ZenTest
% ./x.rb | unit_diff -u

Interesting. I played with this and it’s not quite what I’m looking
for, but it’s nice to have that in my toolkit. Thanks.

You already have the source code. Have you read it? It is called
minitest for a reason. Dig in.

I hadn’t read it. Most source is pretty intimidating at my current
skill level.

I did just now take a look around and I think I found what I’m looking
for.

~/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/minitest/unit.rb

The assert_equal method, and possibly even mu_pp are the two places
I think I could use.

I did some initial playing and the results are already vastly more
readable to me. I’m a bit surprised I was able to do this. Thanks for
the motivation.

On Sun, 27 Mar 2011 05:12:51 +0900
Ryan D. [email protected] wrote:

You don’t actually write your code that way, do you?

More or less. I’m assuming you’re commenting on my general style.
Below would be a full working bit of code. It’s rather pointlessly
simple but it demonstrates my “way”.


require ‘minitest/autorun’

class Whatever

def foo( string )
return string + ‘!’
end

end

class Test_Whatever < MiniTest::Unit::TestCase

def setup()
@o = Whatever.new
end

def test_foo()
assert_equal(
( ‘yay!’ ),
( @o.foo( ‘yay’ ) ),
)
end

end

I’ve taken extreme measures to make my code more readable. While I
have exceptionally lucid times, I often have a very hard time
“fitting a program into my head”.

The real problem arises when I create magical code on one day and then
on some other day I am completely unable to comprehend it.

To help, I’ve been

  • Breaking my problems down into sometimes embarrassingly-small pieces
  • … Each with its own test
  • … Usually with somewhat redundant comments.
  • I’ve also thrown away regular alignment conventions.
  • Ignoring performance improvements, preferring clearer and even
    redundant code. (lots of brackets, stuff on separate lines, trailing
    commas, etc)
  • Using a very small subset of Ruby’s functionality. Doing things with
    brute force and which are far less pretty than possible.

In some cases I might even coerce code into something monstrous like
this:

def test_foo()
assert_equal(
( ‘yay!’ ),
( @o.foo( ‘yay’ ) ),
)
end

The difference to me is that a bunch of programming that initially took
me a very long time has now taken me a very short time to rewrite from
scratch. Think years to weeks. The end result is vastly superior in
every way to me. Faster, clearer, fully tested. Most importantly I’m
enjoying myself!

I know that this means that if I ever manage to function with regular
style conventions I will be forced to re-rewrite everything to follow
them. If it came to that, I would be pleased to do it… I love that
kind of grunt work. =)

I know I’m learning bad habits, my code will be “unreadable” to others,
I may not be able to read the source of others very well, and there are
probably lots of other issues… but I needed a new way to approach
programming. It’s either that or I just give up.

Spiral,

spiralofhope wrote:


class Test_Whatever< MiniTest::Unit::TestCase
end

brute force and which are far less pretty than possible.

I know I’m learning bad habits, my code will be “unreadable” to others,
I may not be able to read the source of others very well, and there are
probably lots of other issues… but I needed a new way to approach
programming. It’s either that or I just give up.

*Hurrrah for you. There is a growing body of people out there who have
realized that shorthand is idiosyncratic and often unreadable except to
the “literati” in any special group. I’ve listened to them since the
days of COBOL (which is still around and fairly healthy) and before. The
problem with COBOL was not it’s verbosity, but it’s lack of modern
structure and object orientation. These deficits have been largely dealt
with in recent versions, so COBOL continues to go forward. The
generation of programmers who wrote COBOL were in many cases converted
accountants and other business types, so they really did not care about
constructs like +=, -=, etc., etc., ad infinitum. What they wanted was
readable code, and through COBOL, they largely got it. Now do understand
that the most horrendous spaghetti code could be written in COBOL, but
there were many who understood that and wrote beautifully structured
code back before that was even a popular term. Now, all that was not
meant to suggest the use of COBOL, but to suggest that maximizing source
code rather than minimizing it will pay off in the long run.

In the day, I was as good as any at writing really tricky, fast, and
short code until I could not move on to other things because no one
could maintain my code but me. Then, I adopted a different idea. Except
for extremely time critical code, I put together the “two o’clock rule”,
which basically said that if this code is not going to look familiar and
largely self documenting at 2am, 6 months from now, I should find
another way to write it. Outside of those critical pieces of code, which
should be documented as heavily as possible, performance should be a
product of the compiler, not the programmer, and that is the weakness of
almost all of the smaller languages, that their compilers just do not
receive the resources necessary to produce really powerful optimization.
Variable names should be largely self-documenting, even if that requires
more characters than the geeks are willing to type, and the omission or
inclusion of some special prefix, post-fix, or infix character should
not change the meaning of the code, especially not in subtle ways. Where
possible, variables should be static rather than dynamic, even if that
means a few extra copies or transforms. At least with static variables,
debugging is a whole lot easier, and compiler level optimization is
orders of magnitude easier. And, for every byte lost to those static
variables, there are a few mega or gigabytes lost to dynamic variables
that are not garbage collected correctly or that are just created in
error.

For all those verbose code sequences (usually much easier for the
compiler to handle) and variables, there are auto-completion
editors/IDE’s that can save most of the keystrokes. Having worked as a
maintenance programmer in my early years and as a diagnostician on just
anything that came by when I was a Senior Systems Programmer, I can
testify to the beauty of the type of code that you are attempting to
apologize for. Keep writing it and try to make it the standard wherever
you work. If the compiler you are using cannot sufficiently optimize,
get another for that language, or get another language, but don’t worry
too much about that side of things. Almost any modern, well supported
language can be used for almost any project, though there are lots of
aspects to such selections. Continue to use as small a subset of the
language as is necessary to keep your code clear and understandable, and
require massive documentation when trickier facets are used.

There will always be coders who can produce unreadable garbage, but
every company who employs such should ride herd on them to do what I
have noted above. It is still true that the cost of writing code is only
10-20% of the life-cycle cost of a program. I have gone so far as to
mandate the use of code beautifiers, so that all code will look like
what you have written. The size of the source code is completely
irrelevant, and the size of the object code is increasingly so.

Everett L.(Rett) Williams II
*

I know I’m learning bad habits, my code will be “unreadable” to others,
I may not be able to read the source of others very well, and there are
probably lots of other issues… but I needed a new way to approach
programming. It’s either that or I just give up.

That’s fine, but then what is the point of this post? Are you asking
for
help with integrating yourself into more of the semantics of the Ruby
Style
way of coding? I guess I’m missing something.

-Nick K.

On Sat, Mar 26, 2011 at 19:33, spiralofhope
<[email protected]

On Sun, 27 Mar 2011 10:55:21 +0900
Nick K. [email protected] wrote:

I know I’m learning bad habits, my code will be “unreadable” to
others, I may not be able to read the source of others very well,
and there are probably lots of other issues… but I needed a new
way to approach programming. It’s either that or I just give up.

That’s fine, but then what is the point of this post? Are you asking
for help with integrating yourself into more of the semantics of the
Ruby Style way of coding? I guess I’m missing something.

It’s just to split off a reply to Ryan from an earlier thread.