Assert Two Point Oh

assert{ 2.0 } is a feeble attempt to declare a "new paradigm" or some such for low-level DeveloperTests. As such it is no competition for BehaviorDrivenDevelopment (which uses DomainSpecificLanguages to occupy the second tier of the TestFoodPyramid), but that doesn't stop BDD proponents from rallying to detract from it.

The root principle of assert{ 2.0 } is that this statement violates DontRepeatYourself:

  assert_equal(42, x)

The inventor of assert{ 2.0 } claims equal repeats the language's natural == operator. So the 2.0 fix is to pass a block into assert, and reflect its entire contents, with their values, at fault time:

  assert{ x == 42 } --> false - should pass
     x   --> 43

This technique obviates all the clutter of assert_operator, assert_less_than, assert_between, assert_responds_to, assert_redirected_to, assert_greater_than, assert_false, assert_nil, assert_not_nil, assert_instance_of, assert_quacks_like, assert_match, assert_no_match, assert_not_equal, assert_door_locked, assert_salad_dressing, assert_shoes_shined, etc. The inventor of assert{ 2.0 } claims you can "just write whatever you like inside the {}, and the assertion will figure out how to reflect its expressions and values if it fails."

Read more about the latest craze among wide-eyed DeveloperTest enthusiasts at http://assert2.rubyforge.org/

Those of you deluded enough to want some 2.0 goodness with your lessor programming languages will just have to rewrite your compilers to not throw away all their tokens at compile time...

-- PhlIp (the inventor of RubyReflector?, the library behind assert{ 2.0 }...)


Uh, PhlIp, I think you just reinvented assert{0.1} with a slightly prettier printer. Not that it was bad, mind you, but it was certainly there first, and this isn't a major step up for it. Admittedly, C lacks the 'block' facility to capture an expression as an object or reflect upon it, but it certainly used those preprocessor macros to good effect.

If you're going to declare a new generation of assert, here's what I want from it:

  assert(x == 42);
  magic;
  assert(x == 43);

I.e. treating it as logical preconditions and postconditions to a directive to the compiler that is essentially: figure out an efficient way to make the postconditions true for me because I'm too lazy to do so myself. This 'assert' would then become a fundamental component of a declarative form of imperative programming best described as GoalBasedProgramming - the postconditions being the goals.

That would be *Unit 2.0. See AgitarsAgitator


I recommend folks look into my CUT package, which uses ASSERT() (in an upcoming later version, ASSERT_() as well, which leaves off the now officially deprecated descriptive comment; the need for the comment is obsoleted by properly named test functions). I force the programmer to just plain use the language-provided boolean operators. There simply is no need to do anything else. Folks interested may find it via Freshmeat, or may link directly via http://www.falvotech.com/content/cut

--SamuelFalvo?

Thanks for your C entry into the Super-High Assertion Reflectivity Contest! I have heard that LispLanguage makes this stuff too easy, and I understand that you are into ForthLanguage, so if you or anyone have any recommendations...

For those who are definitely curious about a nice unit testing solution in Forth, try this one on for size:

 \ Inspired by the works of Jason Woofenden.  However, I cannot
 \ locate his original sources, so I'm recalling off of memory.
 \ -- SamuelFalvo?

: <-- lastxt execute depth 1 xor if -1 abort" STACK IMBALANCE" else 0= abort" TEST FAILED" then ;

\ USAGE:

: DUP-must-duplicate-topmost-stack-item 3 dup = ; <--

: DUP-must-preserve-value-duplicated 3 dup xor 0= ; <--

Notice that <-- causes immediate execution of the word-just-defined (via the lastxt word in GForth; I'm sure other Forths have similar capability), then performs a stack balance check, then performs the actual assertion check.

Unit tests are often kept off in their own little module.

 \ MyModule.fs

: foo .... ; : bar .... ;

\ test-MyModule.fs

marker forget include MyModule.fs

: foo-should-frobnicate-something ... ; <--

: foo-shouldn't-corrupt-memory ... ; <--

: bar-should-break-your-thumbs-when-dropped-from-5-miles-up ... ; <--

: bar-should-get-you-drunk-on-friday-evenings ... ; <--

forget

A "test runner" in Forth could be a single load module that looks like this:

 \ a "test runner", I guess.
 \ No memory leaks, provided you always bracket your code
 \ with a marker word, and you remember to invoke it when
 \ you're done.

include test-MyModule.fs include test-YourModule.fs include test-HisModule.fs include test-HerModule.fs include test-ItsModule.fs

So there you have it; a one-liner unit test framework, which even allows you to run the test runner right as modules are being compiled in production code, and they never take up a byte of memory:

 include MyModule.fs
 include test-MyModule.fs  \ self-forget's so no memory leak.
 include YourModule.fs     \ loads on top of test-MyModule's memory
 include test-YourModule.fs
 include HisModule.fs      \ loads on top of test-YourModule's memory
 include test-HisModule.fs

etc.

The HyperStaticGlobalEnvironment permits effortless mocking of whole modules.

I'll leave it as an exercise to figure out how to do it with LispLanguage (or you can just scrounge around on Google; there are plenty of them out there). --SamuelFalvo?


EditText of this page (last edited March 10, 2008) or FindPage with title or text search