IWETHEY v. 0.3.0 | TODO
1,095 registered users | 0 active users | 0 LpH | Statistics
Login | Create New User
IWETHEY Banner

Welcome to IWETHEY!

New Do I use unit tests?
The latest module I'm working on, which is a complete rewrite of existing functionality (about 5000 lines of uncommented PL/SQL -- without unit tests, incidentally, and completely unmaintainable at this point because it has never been refactored :-P -- being rewritten in Java):

Lines of source code (minus comments): 2269
Lines of unit test code (minus comments): 1894

Answer your question? :-)

Nearly every line of code I write has a unit test. Exceptions, at this point, are web applications containing a lot of Javascript. These are problematic to test in an automated fashion, but we're working on it. I do have "manual" unit tests (which must be run in a browser) for some of that code, however.

Furthermore, unit testing is now an integral part of my development process. I'm not quite as hard core as the XP people would like, but a typical coding session for me involves 1) writing a method, 2) writing a unit test for that method, 3) run test, 4) fix code. Repeat 3 and 4 until the test (and all other tests) passes.

The idea is that you have to test your code anyway. Why not test in a fashion that allows you to easily re-run the tests any time you want, instead of using ad-hoc one-off scripts and visual inspection? And once you've done that, make running the unit tests (which is now very easy to do) an integral part of the process after each piece of code is written. An additional benefit is that you can now change things midstream. If the interface is the same, you can immediately test your changes against the unit tests.

Anecdote: I wrote a list-parsing class two weeks ago. A few days ago, I discovered that it didn't properly parse empty list elements (like one,two,,four - the empty element was being silently dropped), and I had neglected to test for that fact when I wrote the class. So I added a test for that condition, verified it failed, then completely reworked the internals of the parsing method. When I was done, I reran all the tests to verify that 1) the old functionality still worked and 2) I had fixed the defect. The internals of the class were completely refactored. Absolutely no harm was done, because of the unit tests.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Apparently my question sounded dumber than it actually was
I didn't mean to imply that you just ground out code without testing.

I'm always on the lookout for tips and tricks from the professionals that I can pass on to my students, particularly those in their second or third term where they have a good grasp of basic syntax and grammar but lack skill and practice in implementation.

For example, a typical newbie problem is trying to write the entire program all at once instead of phasing in functionality. I have several students right now who are in the habit of doing this and it's taking quite a few sessions of working through problems with them to get this across.

Another phrase I pass on is "Be prepared to throw all the code out and start over."

Recently a student showed me his function for swapping the values of two integer variables:

void swap_int(int& x, int& y)
{
x = y;
y = x;
return;
}

It took me several moments to realize that he wasn't kidding. Then I took him by the hand to the whiteboard with a couple of examples to illustrate why it wasn't working the way he expected.

Granted, his story is atypical. But I think it shows that good coding practice is much more than just knowing the syntax of a language. I'm trying to incorporate examples of good practice in my lessons and talking to people like you who code for a living helps a lot.

Tom Sinclair

"Man, I love it when the complete absence of a plan comes together."
- [link|http://radio.weblogs.com/0104634/|Ernie the Attorney]
New Lessons to be gleaned:

  • Don't write the whole thing before you start testing.

  • When you find a bug, add the test first, verify it fails, then fix until it no longer fails. That way you know you're actually fixing the bug, and not just adding another test that would pass anyway.

  • Use a framework that gets out of the way. Testing will get easier and easier, to the point where it's actually fun. I recommend JUnit and friends; the API is very similar across a gamut of languages. We use the Java and PL/SQL frameworks here; we don't use the C++ framework only because we already had one.

  • Rerun ALL the tests after EVERY change. This is where a unit test becomes a regression test. You want to make sure you didn't break other things by association.

  • Testing enhances maintainability. If you can change something and immediately know if you broke something else, then you're more likely to have confidence in your changes.



I'll add more as I think of it. :-)
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Great stuff!
What about your definition of a 'unit' for testing?

In other words, what amount of code is too small to bother with having its own unit test?

How much code is too big for just one test?

I think you've already established one metric: "One method, one test".

I knew about JUnit already, but can you recommend some similar frameworks for C++? (We start our students out with C++ before moving them to other languages.)
Tom Sinclair

"Of course, just because we've heard a spine-chilling, blood-curdling
scream of the sort to make your very marrow freeze in your bones doesn't
automatically mean there's anything wrong."
-- (Terry Pratchett, Soul Music)
New Re: Great stuff!
[link|http://www.xprogramming.com/software.htm|The mother lode of testing frameworks].

I do a lot of Java unit testing. Here's how I break it down:

1) One matching unit test per class. If the class is Foobar.java, then I have a FoobarTest.java.

2) One suite of tests per package. The suite is a Java unit test that can group other unit test classes. If the package were com.spork.stuffies, with a Foobar.java and a Moobar.java, then I'd have FoobarTest.java, MoobarTest.java, and a StuffiesSuite.java that simply incorporates the FoobarTest and MoobarTest. The tests would all go into the com.spork.stuffies.test package.

3) Within a unit test, I have a set of test methods. The breakdown varies depending on functionality; typically I will group them by function; ie. in the list test class I have a testCreate to test the constructors, testParse to test the parsing, etc. Within each of those methods I will have a series of "make this call, then test the results" blocks. I make use of unique descriptive strings passed with each assert to be able to nail down where a particular test method fails.

4) The need for setup and teardown will affect the number and kind of methods in the unit test class as well. If there is a fair amount of setup, and it has to be done fresh before a test, then that test should have it's own method. The setups and teardowns get run before each test method in the test class.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New C++ unit testing - sounds painful
I mean, the typical failure mode for a C++ program is an unrecoverable core dump. I guess you can use it to test logic errors but you're only getting some of the benefits.

I have to say that the SUnit framework that we are using in Squeak these days is FAB! You run the tests and it puts up a list of failures in a window. Click a failure and the code is rerun and a debugger opens on the entry point for the test. You step in, watch what is going on, fix it as you go, and move on. Coding in the debugger is fun!



"Packed like lemmings into shiny metal boxes.
Contestants in a suicidal race."
    - Synchronicity II - The Police
New More:

  • Test every line of code, but more importantly, test every path through the code.
    Let's say you have the following pseudocode:
    \nif (x == z)\n    // do something with foo\nendif\n\nif (y == q)\n    // do something else with foo\nendif\n\n// do another thing with foo\n

    Then you should have 4 tests for this piece of code: x != z and y != q, x = z and y != q, x != z and y = q, x = z and y = q.

  • Test all boundary conditions. If you have some code like "if (x > 5)", then pass it x = 4, x = 5, and x = 6.

  • Test for null objects. Pass nulls into places and see what happens.

Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Code coverage
I seem to remember tools for this as well. TCov/Gcov?
New How does JUnit (and the like) deal with web pages?
Most of what we write is web pages served up by PHP. Does JUnit allow you to define simulated HTTP POST/GET actions? Does it have a way of running PHP functions that are not called by the web server? (Later versions of PHP work from the command line so this will be less of an issue.)

I know these questions are fairly specific to PHP, which I know you don't do much (at all?). But I have zero experience with testing tools, so don't understand how they can be used to test individual functions within a PHP script.
===

Implicitly condoning stupidity since 2001.
New Not really specific to PHP.
JUnit is a unit testing framework for Java code.

There is a Java framework called [link|http://httpunit.sourceforge.net/|HttpUnit], however, that can do GET, POST, manage cookies, parse HTML, etc. So HttpUnit in conjunction with JUnit is pretty good for testing web pages.

And in fact, looking at that page now for the first time in a few months I see that HttpUnit now [link|http://httpunit.sourceforge.net/doc/Javascript-support.html|supports some Javascript].
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Also from that page
Didn't see that link until after I posted, but there's [link|http://phpunit.sourceforge.net/|PHPUnit]. The docs are kind of sparse. It's hard to tell what are the example class names, and which are the actual PHPUnit classes, but I suppose that will make more sense once I have it installed.
===

Implicitly condoning stupidity since 2001.
New HttpUnit is more useful for integration testing.
I've also used portions of it to simulate a web browser in 'screen-scraping' type applications.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New We use PHPUnit where I work.
If you do any kind of object programming in PHP, it will not be hard to figure out how to use it. We have one file per test class with multiple Test* methods that test things. Just be aware that you can't leave intermediate stuff hanging around between tests - it creates and destroys the test instance for each test.

Wade.

Is it enough to love
Is it enough to breathe
Somebody rip my heart out
And leave me here to bleed
 
Is it enough to die
Somebody save my life
I'd rather be Anything but Ordinary
Please

-- "Anything but Ordinary" by Avril Lavigne.

New I'm experimenting with testing dynamic content ...
When you start using TDD seriously, your coding style changes to accomodate testing. Adding tests to an existing code base is hard. Writing tests as you go is easy.

So, the way you do dynamic content on a web page may change to facilitate the abiliity to test. I've not done any PHP work (so I'm not sure how applicable this is to your situation), but I began experimenting with some dynamic content test first approach. Here's what I'm trying out ...

First you separate your static page data from the dynamic part. We don't really care about testing the static part (why? ... ummm ... because it's static). We do care about making sure the dynamic content is correct however.

I choose to use a template system for the static content. The dynamic part choses the template and defines a set of name/value pairs used to populate the template based upon the input to that web page. Then my unit tests just exercise the dynamic portion and make sure that the proper name/value pairs are supplied with the desired template.

Example ...

\n   class LoginPage < Webpage\n     def update(cgi)\n       if valid_password(cgi['account'], cgi['password'])\n          next_page = select_template('start_screen')\n          next_page['account'] = cgi['account']\n       else\n          next_page = select_template('login_screen')\n         next_page['msg'] = 'invalid login, try again'\\\n       end\n       return next_page\n     end\n   end
And the unit test might look like ...

\n   class LoginPageTest\n     def test_good_login\n       page = LoginPage.new\n       cgi = {'account' => 'jim', 'password' => 'goodpassword'}\n       next_page = page.update(cgi)\n       assert_equal "start_screen", next_page.template_name\n       assert_equal "jim", next_page['account']\n     end\n\n     def test_bad_login\n       page = LoginPage.new\n       cgi = {'account' => 'jim', 'password' => 'boguspassword'}\n       next_page = page.update(cgi)\n       assert_equal "login_screen", next_page.template_name\n       assert_match /invalid login/, next_page['msg']\n     end\n   end
That's just a sketch of what I'm trying. I've glossed over some details. Any feedback is welcome.
--
-- Jim Weirich jweirich@one.net [link|http://w3.one.net/~jweirich|http://w3.one.net/~jweirich]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
New Can I quote this thread?
I'd like to take the tips/tricks/best practice suggestions from this thread and compile them into a handout for my students.

If you've replied already or are planning to reply to this thread, please let me know if you'd rather I not use your remarks.

I'll edit a bit to eliminate off-topic, non-technical points and if you wish, I can post the compilation for approval here.

I'm pushing to have our programming curriculum include more real-world best practice topics and this would be a great start. My program director agrees with me and now it's a matter of selling it to the other faculty and the students.

Tom Sinclair

"Man, I love it when the complete absence of a plan comes together."
- [link|http://radio.weblogs.com/0104634/|Ernie the Attorney]
New Even better:
Compose your compilation, and post it on [link|http://twiki.iwethey.org/twiki/bin/view/Main/|TWikIWETHEY]. :-)

But yes, you have my permission. The more people using testing, the better.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New No, you can't use my comments
After all, it's not like I posted them to a publicly accessible place or anything. Oh wait ...









































[image|/forums/images/warning.png|0|This is sarcasm...]
===

Implicitly condoning stupidity since 2001.
New Thanks!
I'll see what I can put together this weekend.

Tom Sinclair

"Man, I love it when the complete absence of a plan comes together."
- [link|http://radio.weblogs.com/0104634/|Ernie the Attorney]
New A TDD Example
tjsinclair: I'd like to take the tips/tricks/best practice suggestions from this thread and compile them into a handout for my students.

If you are interested, I have a laboriously detailed account of a pair programming session at one of our XP user group meetings. Lots of test-first design examples and some refactorings are given. Feel free to use whatever you need.

Here's the URL: [link|http://w3.one.net/~jweirich/talks/tdddemo/index.html|http://w3.one.net/~j...dddemo/index.html]

(Note: that URL should be good until mid month when my ISP upgrades me from 100 Megabytes to 5 Megabytes of web storage. Needless to say, I'm working on getting a new site, but it won't be ready for a week or two).
--
-- Jim Weirich jweirich@one.net [link|http://w3.one.net/~jweirich|http://w3.one.net/~jweirich]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
New Ooh, he left out the ^

and a line

void swap_int(int& x, int& y)
{
x ^= y;
y ^= x;
x ^= y;
}



"Packed like lemmings into shiny metal boxes.
Contestants in a suicidal race."
    - Synchronicity II - The Police
New That's just evil to the core. :-)
New It's C++, what do you expect?



"Packed like lemmings into shiny metal boxes.
Contestants in a suicidal race."
    - Synchronicity II - The Police
New I would only use that if it were properly commented.

Is it enough to love
Is it enough to breathe
Somebody rip my heart out
And leave me here to bleed
 
Is it enough to die
Somebody save my life
I'd rather be Anything but Ordinary
Please

-- "Anything but Ordinary" by Avril Lavigne.

New I'd probably never use it at all
Its a cool parlor trick I think. Thats about it.



"Packed like lemmings into shiny metal boxes.
Contestants in a suicidal race."
    - Synchronicity II - The Police
New Its a cool parlor trick...
...that has an annoying tendancy to show up on the [insert correct TLA here; the name of the test that you have to take to get into a Master's program] test.

(This gettin old just isn't what it's cracked up to be...)
jb4
"We continue to live in a world where all our know-how is locked into binary files in an unknown format. If our documents are our corporate memory, Microsoft still has us all condemned to Alzheimer's."
Simon Phipps, SUN Microsystems
New Not even really a C++ issue as such, is it?
You can do that evil thing he did in ANSI C with pointers.

Have you seen this?

\nregister n = (count + 7) / 8;      /* count > 0 assumed */\n\n   switch (count % 8)\n   {\n   case 0:        do {  *to = *from++;\n   case 7:              *to = *from++;\n   case 6:              *to = *from++;\n   case 5:              *to = *from++;\n   case 4:              *to = *from++;\n   case 3:              *to = *from++;\n   case 2:              *to = *from++;\n   case 1:              *to = *from++;\n                      } while (--n > 0);\n   }\n


Now THAT is evil!
-drl
New Its a Duff Device
and as an optimization for moving chunks of data rapidly its pretty good.




"Packed like lemmings into shiny metal boxes.
Contestants in a suicidal race."
    - Synchronicity II - The Police
New Yep - it's assembler in C
-drl
New Most ASM Languages have a SWAP instruction.
New Yes, not my point
My point was that C is syntactically capable of these kinds of weird things you might use at a very low level.
-drl
New And my point...
... (if there's really a point to be made) is that this is even lower level than assembly language (unless you count the One Instruction Machine). More like programming ASIC's. :-)
New SWAP?
SWAP? Did you mean MOVB/MOVW?
--
-- Jim Weirich jweirich@one.net [link|http://w3.one.net/~jweirich|http://w3.one.net/~jweirich]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
New That's ANSI C?!?
ANSI C compilers I've run across recently wouldn't allow you to put a
case
label inside of a block (i.e. inside of an open curly brace).

I know ANSI C++ won't let you...
jb4
"We continue to live in a world where all our know-how is locked into binary files in an unknown format. If our documents are our corporate memory, Microsoft still has us all condemned to Alzheimer's."
Simon Phipps, SUN Microsystems
Expand Edited by jb4 May 14, 2003, 01:46:33 PM EDT
New That's ANSI C?!? ... YES
I just tried it undef GNU C++, GNU C and Solaris C++. Duff's device works fine under all of them.

(NOTE: I had to change "register n" to "register int n" for it to work in C++).
--
-- Jim Weirich jweirich@one.net [link|http://w3.one.net/~jweirich|http://w3.one.net/~jweirich]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
Expand Edited by JimWeirich May 14, 2003, 01:58:08 PM EDT
New Re: That's ANSI C?!?
No, it's antsy C!

Took me a while to figure out what the hell it was for the first time I saw it.
-drl
     Cringely on Refactoring - (tjsinclair) - (41)
         He's still skirting the real issues to make his "point". - (admin) - (39)
             Good point - (tjsinclair) - (38)
                 Do I use unit tests? - (admin) - (34)
                     Apparently my question sounded dumber than it actually was - (tjsinclair) - (33)
                         Lessons to be gleaned: - (admin) - (16)
                             Great stuff! - (tjsinclair) - (2)
                                 Re: Great stuff! - (admin)
                                 C++ unit testing - sounds painful - (tuberculosis)
                             More: - (admin) - (1)
                                 Code coverage - (Simon_Jester)
                             How does JUnit (and the like) deal with web pages? - (drewk) - (5)
                                 Not really specific to PHP. - (admin) - (3)
                                     Also from that page - (drewk) - (2)
                                         HttpUnit is more useful for integration testing. - (admin)
                                         We use PHPUnit where I work. - (static)
                                 I'm experimenting with testing dynamic content ... - (JimWeirich)
                             Can I quote this thread? - (tjsinclair) - (4)
                                 Even better: - (admin) - (2)
                                     No, you can't use my comments - (drewk)
                                     Thanks! - (tjsinclair)
                                 A TDD Example - (JimWeirich)
                         Ooh, he left out the ^ - (tuberculosis) - (15)
                             That's just evil to the core. :-) -NT - (ChrisR) - (1)
                                 It's C++, what do you expect? -NT - (tuberculosis)
                             I would only use that if it were properly commented. -NT - (static) - (12)
                                 I'd probably never use it at all - (tuberculosis) - (11)
                                     Its a cool parlor trick... - (jb4) - (10)
                                         Not even really a C++ issue as such, is it? - (deSitter) - (9)
                                             Its a Duff Device - (tuberculosis) - (5)
                                                 Yep - it's assembler in C -NT - (deSitter) - (4)
                                                     Most ASM Languages have a SWAP instruction. -NT - (ChrisR) - (3)
                                                         Yes, not my point - (deSitter) - (1)
                                                             And my point... - (ChrisR)
                                                         SWAP? - (JimWeirich)
                                             That's ANSI C?!? - (jb4) - (2)
                                                 That's ANSI C?!? ... YES - (JimWeirich)
                                                 Re: That's ANSI C?!? - (deSitter)
                 Re: Good point - (JimWeirich) - (2)
                     Another good point - (admin) - (1)
                         Me too. - (static)
         FWIW, Squeak is undergoing a huge refactoring effort - (tuberculosis)

Thine is a mere venal sin which may be atoned: dast not move it very far or very often, or Ever! -- to the 7-11 for a Big G{ulp..} and a Lottery ticket. This be thy penance.
287 ms