Loading ...
Sorry, an error occurred while loading the content.

Re: [extremeperl] unit tester

Expand Messages
  • Adam Sroka
    ... I can t recall the last time I opened a test and didn t know what it was testing, but if this ever happened I suppose my response would go something like
    Message 1 of 33 , Aug 29, 2005
      Rob Nagler wrote:

      > We have about 12,000 lines of unit tests. We have 1,500 lines
      >(including lengthy pod) of test framework. I would estimate that
      >we have 50% fewer lines of unit test code than if we had used an
      >imperative framework. That's a total savings of about 4,000 lines.
      >More importantly, when I look at a test, I see what it is testing.
      I can't recall the last time I opened a test and didn't know what it was
      testing, but if this ever happened I suppose my response would go
      something like this: I would go to the thing under test and start
      deleting parts of it until something broke. Hopefully, by then I would
      have figured out what the test was doing and been able to refactor it.
      All the while, I would complain loudly, and, usually, the person who
      wrote the code would come to their own defense providing an explanation
      of why they wrote what they wrote. When they don't it's usually because
      it was me.

      >>use Test::More qw(no_plan);
      >This actually is a very important part of the framework. You need to
      >know what you are measuring before you know whether your test works or
      I am doing TDD, I know what I am testing. I am testing the thing that
      doesn't exist now, but will when the test passes. I don't need to have a
      number that I change every time I run the test. If I added a test then I
      have one more than I did last time I ran the test. Otherwise I have the
      same number. Test::Harness (via prove) will tell me the exact number.

      >If you write procedural code, the nature of testing is procedure. The
      >problem with procedural code is that it is stateful. The most
      >difficult problems to debug are caused by impliciting coupling of
      >shared state. If you look at the latest bOP release, you'll notice
      >that I fixed several defects by changing implicit to explicit
      >The way you couple your code is important. Back to the test example
      >from my book (http://www.extremeperl.org/bk/test-driven-design):
      > use strict;
      > use Test::More tests => 9;
      > use Test::Exception;
      > BEGIN {
      > use_ok('EMA');
      > }
      > ok(my $ema = EMA->new(4));
      > is($ema->compute(5), 5);
      > is($ema->compute(5), 5);
      > is($ema->compute(10), 7);
      >The use of $ema is implicit coupling. My book uses procedural code,
      >because it is my weak attempt at "being popular" (see
      >paulgraham.com). Here's how it is written in the version available in
      > use strict;
      > use Bivio::Test;
      > Bivio::Test->new('Bivio::Math::EMA')->unit([
      > 4 => [
      > compute => [
      > 5 => 5,
      > 5 => 5,
      > 10 => 7,
      > ],
      > ],
      > ]);
      >Note the explicit relationship between the object created (with 4) and
      >the method (compute) called repeatedly on that object. In both
      >versions, the code must be executed imperatively. However, in the
      >declarative version, you are shown the relationship through the
      >explicit nesting of a perl data structure. You can't call the wrong
      >method, becuse it is mentioned only once. You can't use the wrong
      >object, because it is declared only once. In the first version, it's
      >much easier to have a mistake like this.
      Hmm... three different tests, three different method calls. Makes sense
      to me. Your approach is still performing three different tests, but you
      are HIDING this fact in your implementation. IMHO, your approach is LESS
      clear. As for the issue of state, if $ema has some state that is
      maintained from one invocation to the next the test should make that
      clear. The way the test is written does not call for any state,
      therefore you shouldn't implement any. If you do, you are NOT doing TDD.

      >>needs to be an object, then I make one. That is the essence of XP - do
      >>the simplest thing that could possibly work. Most unit tests in other
      >>languages feel like procedures wrapped in classes anyway (e.g. TestCase
      >>feels more like a collection of testThis() methods than a proper class.)
      >You are correct, which is exactly the problem. When you find yourself
      >typing testThis, testThat, and testTheOtherThing, you are repeating
      >yourself. The rule of three says you need to get rid of the word
      >"test", and there is probably a strong relationship between This,
      >That, and TheOtherThing.
      I think you are taking the idea of duplication a little too far.
      Duplication is okay when it conveys something useful. For example, if I
      have three things to test I write three tests. It is clear to everyone
      who reads my test code that it contains three tests. This is a good thing.

      >>Your code is every bit as repetitive as the code you are replacing. The
      >>difference is that you've dropped in a layer of abstraction
      >>(unnecessarily, IMO) between your repetitive test code and the main
      >>package. Test code is repetitive because testing is repetitive. You can
      >>hide that, but you haven't changed it.
      >There are two reasons I see for using classes: sharing and naming.
      Since I am using Test::* packages from CPAN, I am fairly sure that the
      framework is well shared. I am also pretty sure that other perl
      programmers will understand the tests I have written. As for naming, I
      keep my test files small, one per thing (Class, Package, Script, etc.)
      under test. I also keep my fixtures in the smallest lexical scope

      I use classes a lot. I use them when I have data with particular
      semantics and I don't want to worry about the details of its behavior
      every time I use it. I just want to call it and have it do the right
      thing. "Test" does not meet my criteria:

      1) it doesn't encapsulate any data
      2) if there is no data, then there is no behavior associated with that data
      3) in fact, test is a behavior the result of which is true or false
      (pass or fail). It takes data (The thing to test) and returns a result.
      It is a function/method/procedure not a class. Forcing "Test" to be a
      class is a kludge, IMO.
    • Dave Cross
      ... You didn t get a reply to this. I hope this isn t too late to be useful. prove is a command line test runner. It s included with recent versions of
      Message 33 of 33 , Sep 14, 2005
        Terrence Brannon wrote:
        > Adam Sroka <adam.s@...> writes:
        >>I just use Test::More and prove.
        > what is prove? I could not find it in the main Test::More docs:
        > http://search.cpan.org/~mschwern/Test-Simple-0.60/lib/Test/More.pm

        You didn't get a reply to this. I hope this isn't too late to be useful.

        prove is a command line test runner. It's included with recent versions
        of Test::Harness.


      Your message has been successfully submitted and would be delivered to recipients shortly.