Page 2 of 2

Re: Help getting started with unit testing

Posted: Fri Apr 18, 2008 12:00 pm
by RobertGonzalez
Ok, I never intended this discussion to head down the TDD path, but since it has taken that turn maybe we can look at it a little closer. My understanding of TDD is rather limited so I am throwing this out there as a series of questions...

et's say we are building a string object (for the sake of this question). To build the unit tests in a TDD fashion you would create a minimal class structure with one method that essentially returns true and test that, correct? So we would start off like this:

Code: Select all

<?php
class String {
  public function __construct() {
  }
 
  public function hasString() {
    return true;
  }
}
?>
So now there is a skeleton of a class and we can set up a unit test like this:

Code: Select all

<?php
class StringTests extends UnitTestCase {
  function TestString() {
    $string = new String();
    $this->assertTrue($string->hasString());
  }
}
?>
So now the unit test passes. The goal now is to make the unit test fail then refactor the code so the unit test passes again. Or is that not correct?

Code: Select all

<?php
class String {
  public $string = null;
 
  public function __construct() {
  }
 
  public function hasString() {
    return null !== $this->string;
  }
}
?>
So now the test fails so we need to rework the code so that it doesn't fail anymore. Is this correct?

Code: Select all

<?php
class String {
  public $string = null;
 
  public function __construct($string = null) {
    $this->string = $string;
  }
 
  public function hasString() {
    return null !== $this->string;
  }
}
?>
And this would be a modified unit test:

Code: Select all

<?php
class StringTests extends UnitTestCase {
  function TestString() {
    $string = new String('Hello World');
    $this->assertTrue($string->hasString());
  }
}
?>
Is this a correct approach to TDD (or something similar)?

Re: Help getting started with unit testing

Posted: Fri Apr 18, 2008 12:20 pm
by RobertGonzalez
Ok, another little bit... if we had a snippet and wanted to write test cases for it after the fact (like in my original question), is this a decent approach:

Code: Select all

<?php
class String {
  public $string = null;
  protected $_length = 0;
 
  public function __construct($string = '') {
    $this->setString($string);
  }
  
  public function setString($string) {
    $this->string = $string;
    $this->_setLength();
  }
 
  public function hasString() {
    return null !== $this->string;
  }
  
  protected function _setLength() {
    $this->_length = strlen($this->string);
  }
  
  public function length() {
    return $this->_length;
  }
  
  public function getChar($pos) {
    if (!is_numeric($pos)) {
      $pos = intval($pos);
    }
    
    if ($pos < $this->_length) {
        return $this->string[$pos];
    }
    
    return null;
  }
  
  protected function _setLength() {
    $this->_length = strlen($this->string);
  }
}
?>

Code: Select all

<?php
class StringTests extends UnitTestCase {
  function TestString() {
    $string = new String();
    $this->assertFalse($string->hasString());
    
    $test = 'Hello World';
    $string->string = $test;
    $this->assertString($string->hasString());
    $this->assertEqual($string->length(), strlen($test));
    $this->assertEqual($string->getChar(4), $test[4]);
    
    $string->string = null;
    $this->assertFalse($string->hasString());
  }
}
?>

Re: Help getting started with unit testing

Posted: Fri Apr 18, 2008 12:37 pm
by Christopher
Everah wrote:Ok, I never intended this discussion to head down the TDD path, but since it has taken that turn maybe we can look at it a little closer. My understanding of TDD is rather limited so I am throwing this out there as a series of questions...
I think my point Everah, was that heading in the TDD direction first is a bad idea for most people. If you look at what you posted -- the code is first and the tests are second. You did not use TDD to design. In fact you could not use TDD to design because you don't know how to test well yet. My suggestion is: learn to test first ... use that to improve your design skills ... then learn to combine them.
Chris Corbyn wrote:I think this was the key point -- starting from the start. If you've never TDD'd before, trying to start halfway through a project will just put you off. Mostly because everything that was developed prior to the employment of TDD won't be very test-friendly.
The reason is that TDD is a DESIGN practice, not a coding practice. That is regularly forgotten and not mentioned in this discussion. And GOOD DESIGN is an almost impossible thing to teach. As I said, 2% are natural at it; many others learn it the hard way; most never really design well.
Chris Corbyn wrote:I think (b) is the most important thing to get the hang of. ~arborint's first example he posted was a good demonstration of where you can trip up. Although this was only for testing a really simple concept, there were tests for two different scenarios/behaviours in the same test method. In a more complex scenario a failing test with multiple behavioural expectations in it would cause confusion. The more methods you have like that the worse if gets.
That's because I was not doing TDD. I was giving some examples of the thought processes that unit testing makes you go through. Writing unit tests gets you to look at your code differently. In this case it exposes the design. That's not tripping up at all. That is a step to understanding design that you need to do before ever understanding TDD.
Chris Corbyn wrote:Writing unit tests very badly often just makes your work load increase since you spend more time maintaining your broken tests than you do maintaining the source code. I can give a classic example of something I fix in other people's tests at work all the time. We have some actual system tests (to supplement our units) which really do connect to a database full of test data. Before each test method runs the DB is wiped and the schema/data is re-imported. A common fragile test scenario I run into with this set up is people making assertions about exact row counts in the test data. Of course, when someone adds their own test data this breaks that test. There are all kinds of things you can do badly which just cause tests to break all the time when the system still works as expected... learning to avoid the situations just comes with practise.
Again, you like most people who understand testing are very quickly way out in front of what anyone trying to understand testing can practically understand. You are telling people that don't yet know how to test that writing poor test is worse than no tests -- but they will start by writing poor tests. So you have given them a reason to stop testing because it takes some time before you start writing test at the level you are discussing. This gets back to my point. Testers who never had to crawl because they just got it have a hard time understanding that most people need to crawl first.

Re: Help getting started with unit testing

Posted: Fri Apr 18, 2008 12:57 pm
by arjan.top
@Everah:

1. write test
2. watch it fail
3. make it pass
4. refactor
5. repeat

Once your test passes it it should never fail again (kent beck's style :) )

Re: Help getting started with unit testing

Posted: Mon Apr 21, 2008 4:15 am
by Jenk
Chris Corbyn wrote:I don't know anybody who used it properly and went back though ;)
That is what I implied :p