TDD, I love you

Discussion of testing theory and practice, including methodologies (such as TDD, BDD, DDD, Agile, XP) and software - anything to do with testing goes here. (Formerly "The Testing Side of Development")

Moderator: General Moderators

User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

TDD, I love you

Post by Chris Corbyn »

I just have to say that test driven development tonight gave me the biggest benefit it has done to date! I've spent the past couple of weeks on and off refactoring a massive code base which involved some fairly impressive interface changes. All my tests exploded initially (fantastic, I'd hope so too) but as the code gradually came back together the failing tests disappeared one by one. Today I finished off my refactoring, 100% passing tests, and only then did I realise "hey, I haven't even tried this stuff for real other than watching tests pass/fail". So I ran my smaller set of smoke tests which are basically my end-to-end tests, and voila, everything works like it did before I refactored :)

I can say for sure that without the 77 test cases this library has I would never have even dared attempt the scale or refactoring I did.

I know it's obvious that testing helps in this case, but when you finally get that level of support back out of your tests you have to take a bow to all the TDD proponents who's test infected attitude rubbed off on you in the first place :D

Code: Select all

w3style-2:se d11wtq$ php test-suite/run.php
All Tests
  >> Swift_MailerTest OK
  >> Swift_MimeFactoryAcceptanceTest OK
  >> Swift_TransportFactoryAcceptanceTest OK
  >> Swift_ByteStream_ArrayByteStreamTest OK
  >> Swift_ByteStream_FileByteStreamAcceptanceTest OK
  >> Swift_CharacterReader_GenericFixedWidthReaderTest OK
  >> Swift_CharacterReader_UsAsciiReaderTest OK
  >> Swift_CharacterReader_Utf8ReaderTest OK
  >> Swift_CharacterReaderFactory_SimpleCharacterReaderFactoryAcceptanceTest OK
  >> Swift_CharacterStream_ArrayCharacterStreamTest OK
  >> Swift_Encoder_Base64EncoderAcceptanceTest OK
  >> Swift_Encoder_Base64EncoderTest OK
  >> Swift_Encoder_QpEncoderAcceptanceTest OK
  >> Swift_Encoder_QpEncoderTest OK
  >> Swift_Encoder_Rfc2231EncoderAcceptanceTest OK
  >> Swift_Encoder_Rfc2231EncoderTest OK
  >> Swift_Events_CommandEventTest OK
  >> Swift_Events_EventObjectTest OK
  >> Swift_Events_ResponseEventTest OK
  >> Swift_Events_SendEventTest OK
  >> Swift_Events_SimpleEventDispatcherTest OK
  >> Swift_Events_TransportChangeEventTest OK
  >> Swift_Events_TransportExceptionEventTest OK
  >> Swift_KeyCache_ArrayKeyCacheAcceptanceTest OK
  >> Swift_KeyCache_ArrayKeyCacheTest OK
  >> Swift_KeyCache_DiskKeyCacheAcceptanceTest OK
  >> Swift_KeyCache_SimpleKeyCacheInputStreamTest OK
  >> Swift_Mailer_ArrayRecipientIteratorTest OK
  >> Swift_Mime_AttachmentAcceptanceTest OK
  >> Swift_Mime_AttachmentTest OK
  >> Swift_Mime_EmbeddedFileAcceptanceTest OK
  >> Swift_Mime_EmbeddedFileTest OK
  >> Swift_Mime_MimePartAcceptanceTest OK
  >> Swift_Mime_MimePartTest OK
  >> Swift_Mime_SimpleMessageAcceptanceTest OK
  >> Swift_Mime_SimpleMessageTest OK
  >> Swift_Mime_SimpleMimeEntityAcceptanceTest OK
  >> Swift_Mime_SimpleMimeEntityTest OK
  >> Swift_Mime_ContentEncoder_Base64ContentEncoderAcceptanceTest OK
  >> Swift_Mime_ContentEncoder_Base64ContentEncoderTest OK
  >> Swift_Mime_ContentEncoder_PlainContentEncoderAcceptanceTest OK
  >> Swift_Mime_ContentEncoder_PlainContentEncoderTest OK
  >> Swift_Mime_ContentEncoder_QpContentEncoderAcceptanceTest OK
  >> Swift_Mime_ContentEncoder_QpContentEncoderTest OK
  >> Swift_Mime_Header_DateHeaderTest OK
  >> Swift_Mime_Header_IdentificationHeaderTest OK
  >> Swift_Mime_Header_MailboxHeaderTest OK
  >> Swift_Mime_Header_ParameterizedHeaderTest OK
  >> Swift_Mime_Header_PathHeaderTest OK
  >> Swift_Mime_Header_UnstructuredHeaderTest OK
  >> Swift_Mime_Header_VersionHeaderTest OK
  >> Swift_Mime_HeaderEncoder_Base64HeaderEncoderTest OK
  >> Swift_Mime_HeaderEncoder_QpHeaderEncoderTest OK
  >> Swift_Plugins_AntiFloodPluginTest OK
  >> Swift_Plugins_BandwidthMonitorPluginTest OK
  >> Swift_Plugins_DecoratorPluginTest OK
  >> Swift_Plugins_LoggerPluginTest OK
  >> Swift_Plugins_ReporterPluginTest OK
  >> Swift_Plugins_ThrottlerPluginTest OK
  >> Swift_Plugins_Loggers_ArrayLoggerTest OK
  >> Swift_Plugins_Reporters_HitReporterTest OK
  >> Swift_Plugins_Reporters_HtmlReporterTest OK
  Smoke Test
  Compare email sent with image @ http://swiftmailer.org/smoke/4.0.0/attachment.jpg
  >> Swift_Smoke_AttachmentSmokeTest OK
  Smoke Test
  Compare email sent with image @ http://swiftmailer.org/smoke/4.0.0/basic.jpg
  >> Swift_Smoke_BasicSmokeTest OK
  Smoke Test
  Compare email sent with image @ http://swiftmailer.org/smoke/4.0.0/international.jpg
  >> Swift_Smoke_InternationalSmokeTest OK
  >> Swift_Transport_EsmtpTransportTest OK
  >> Swift_Transport_FailoverTransportTest OK
  >> Swift_Transport_LoadBalancedTransportTest OK
  >> Swift_Transport_SendmailTransportTest OK
  >> Swift_Transport_Esmtp_AuthHandlerTest OK
  >> Swift_Transport_Esmtp_Auth_CramMd5AuthenticatorTest OK
  >> Swift_Transport_Esmtp_Auth_LoginAuthenticatorTest OK
  >> Swift_Transport_Esmtp_Auth_PlainAuthenticatorTest OK
  >> Swift_Transport_PolymorphicBuffer_BasicSocketAcceptanceTest OK
  >> Swift_Transport_PolymorphicBuffer_ProcessAcceptanceTest OK
  >> Swift_Transport_PolymorphicBuffer_SslSocketAcceptanceTest OK
  >> Swift_Transport_PolymorphicBuffer_TlsSocketAcceptanceTest OK
OK
Test cases run: 77/77, Passes: 5280, Failures: 0, Exceptions: 0
$w3style-2:se d11wtq$ svn commit -m "PHEWW!! Seriously, I thought that refactoring was going to take forever. Massive refactoring in the header-entity interaction. I like it now :)"
Sending        TODO
Sending        lib/classes/Swift/Mime/Attachment.php
Adding         lib/classes/Swift/Mime/CharsetObserver.php
Sending        lib/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php
Sending        lib/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php
Sending        lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php
Sending        lib/classes/Swift/Mime/ContentEncoder.php
Adding         lib/classes/Swift/Mime/EncodingObserver.php
Deleting       lib/classes/Swift/Mime/FieldChangeObserver.php
Sending        lib/classes/Swift/Mime/Header/DateHeader.php
Sending        lib/classes/Swift/Mime/Header/IdentificationHeader.php
Sending        lib/classes/Swift/Mime/Header/MailboxHeader.php
Sending        lib/classes/Swift/Mime/Header/ParameterizedHeader.php
Sending        lib/classes/Swift/Mime/Header/PathHeader.php
Sending        lib/classes/Swift/Mime/Header/UnstructuredHeader.php
Sending        lib/classes/Swift/Mime/Header/VersionHeader.php
Sending        lib/classes/Swift/Mime/Header.php
Sending        lib/classes/Swift/Mime/MimeEntity.php
Sending        lib/classes/Swift/Mime/MimePart.php
Adding         lib/classes/Swift/Mime/ParameterizedHeader.php
Sending        lib/classes/Swift/Mime/SimpleMessage.php
Sending        lib/classes/Swift/Mime/SimpleMimeEntity.php
Sending        tests/acceptance/Swift/Mime/SimpleMimeEntityAcceptanceTest.php
Sending        tests/unit/Swift/CharacterStream/ArrayCharacterStreamTest.php
Adding         tests/unit/Swift/Mime/AbstractMimeEntityTest.php
Sending        tests/unit/Swift/Mime/AttachmentTest.php
Sending        tests/unit/Swift/Mime/ContentEncoder/QpContentEncoderTest.php
Sending        tests/unit/Swift/Mime/EmbeddedFileTest.php
Sending        tests/unit/Swift/Mime/Header/DateHeaderTest.php
Sending        tests/unit/Swift/Mime/Header/IdentificationHeaderTest.php
Sending        tests/unit/Swift/Mime/Header/MailboxHeaderTest.php
Sending        tests/unit/Swift/Mime/Header/ParameterizedHeaderTest.php
Sending        tests/unit/Swift/Mime/Header/PathHeaderTest.php
Sending        tests/unit/Swift/Mime/Header/UnstructuredHeaderTest.php
Sending        tests/unit/Swift/Mime/MimePartTest.php
Sending        tests/unit/Swift/Mime/SimpleMessageTest.php
Sending        tests/unit/Swift/Mime/SimpleMimeEntityTest.php
Transmitting file data ....................................
Committed revision 720.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Re: TDD, I love you

Post by Jenk »

It's certainly good stuff. Another massive benefit I've seen first hand is within a shared development environment. We have multiple developers (within the same team) working on multiple projects, sometimes we interchange projects multiple times within the same working day, depending on the priority of our user stories (teams are based on skill set and not client/project).

I can safely say the one thing keeping all of that flowing is tests/specs/fixtures. If it were not for the specs, we would not know if what we have just committed breaks others changes, we would not know if what we just loaded breaks our changes. If it were not for fixtures and specs, transforming stories into code would take a lot longer than it does, and creating specs before we begin changes also helps us estimate time to complete the story a lot more accurately.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Re: TDD, I love you

Post by Ambush Commander »

Hear hear! You don't really appreciate automated regression testing until you actually have to change the code. :-)
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: TDD, I love you

Post by Chris Corbyn »

Not wanting to draw traffic away from devnetwork, but I also started this same thread on SitePoint when I posted this one. It's a pretty lively thread if anybody was interested in continuing to read.

http://www.sitepoint.com/forums/showthread.php?t=539572
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Re: TDD, I love you

Post by Jenk »

One thing I will say I don't like about B/TDD is when I write a test, then the code to satisfy it, and it passes first time.. I then have to spend a few minutes satisfying myself that I have actually passed the test and haven't circumvented it in a silly way. :crazy: :lol:
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Re: TDD, I love you

Post by matthijs »

Somebody should write a book purely on TDD in PHP. Selling that will make you very rich. I mean, everybody wants to learn it but there are so little good resources online. A few books discuss it a bit but that's all.
User avatar
arjan.top
Forum Contributor
Posts: 305
Joined: Sun Oct 14, 2007 4:36 am
Location: Hoče, Slovenia

Re: TDD, I love you

Post by arjan.top »

you don't need books for TDD in PHP, it is mostly the same in any language you choose

Most of the books are for java ...
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: TDD, I love you

Post by Chris Corbyn »

arjan.top wrote:you don't need books for TDD in PHP, it is mostly the same in any language you choose

Most of the books are for java ...
Agreed. All the frameworks are just about xUnit standard anyway. Reading a Java book (on JUnit) will teach you just as much :)

A java test case:

[java]class MyTestCase extends UnitTestCase {  private SUT _sut;    public void setUp() {    _sut = new SUT();  }  public void testSUTStartsInactive() {    assertFalse("SUT should be inactive", _sut.isActive());  }}[/java]

A PHP test case:

Code: Select all

class MyTestCase extends UnitTestCase {
  private $_sut;
  
  public function setUp() {
    $this->_sut = new SUT();
  }
 
  public function testSUTStartsInactive() {
    $this->assertFalse($this->_sut->isActive(), 'SUT should be inactive');
  }
}
I am aware the assertFalse() parameters are back to front. There are subtle differences like that.
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Re: TDD, I love you

Post by matthijs »

I did not say that you can't learn TDD using Java books. I just said that there is currently no single book dedicated to TDD in PHP. And that there might be a market.

I mean, a new book on "Building websites using PHP and mysql" appears about monthly or so. There must be hundreds of them by now. Why not one single book on TDD?

The point is not that picking up a Java book would teach me something (it will), but it would be nice to have one directed at PHP. Not having to deal with the (subtle) differences, being able to directly apply the code examples, etc would be very nice.
I do have a feeling, and maybe I'm completely wrong, that interest in TDD has increased/is increasing. PHP is a popular language, with a very low barrier to enter. So millions of people have picked up the language by reading a few articles and asking some question on a forum. But what if you want to take that next step? Of course, again, you can all do it your self and learn it in other ways. But if I find it more comfortable to sit on my couch by the fire and learn a bit by reading a nice book, who will stop me?

But well, maybe I'm the only one :)
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Re: TDD, I love you

Post by Kieran Huggins »

embarrassing admission: I have never used testing... but between your success story and ole's constant peer pressure I'll start with my next project.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Re: TDD, I love you

Post by Jenk »

matthijs wrote:I did not say that you can't learn TDD using Java books. I just said that there is currently no single book dedicated to TDD in PHP. And that there might be a market.

I mean, a new book on "Building websites using PHP and mysql" appears about monthly or so. There must be hundreds of them by now. Why not one single book on TDD?

The point is not that picking up a Java book would teach me something (it will), but it would be nice to have one directed at PHP. Not having to deal with the (subtle) differences, being able to directly apply the code examples, etc would be very nice.
I do have a feeling, and maybe I'm completely wrong, that interest in TDD has increased/is increasing. PHP is a popular language, with a very low barrier to enter. So millions of people have picked up the language by reading a few articles and asking some question on a forum. But what if you want to take that next step? Of course, again, you can all do it your self and learn it in other ways. But if I find it more comfortable to sit on my couch by the fire and learn a bit by reading a nice book, who will stop me?

But well, maybe I'm the only one :)
T/BDD is more about the development cycle than it is about actual code. Infact, there's very little discussion anywhere about T/BDD that is about the code, unless it is for a specific testing framework.
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Re: TDD, I love you

Post by matthijs »

Jenk wrote:T/BDD is more about the development cycle than it is about actual code. Infact, there's very little discussion anywhere about T/BDD that is about the code, unless it is for a specific testing framework.
Ok, that's true. But still, having a bit more information then a smallish chapter in the end of a PHP book which says "By the way, if you really want to write good code, use TDD and subversion" would be nice I think. Again, I will get there without a nice book. I'll try things out, read whatever is available, scattered over the place, and learn it that way. It's just my signal that I think that there's a "market" for good info on this subject and there's currently very little "supply". Maybe I'm wrong. Or not.

A while ago there were a few TDD threads on the sitepoint forum in which one member started by posing a problem and then others would help him do a "live" TDD session, by discussing what should be tested, how, etc. I found that pretty cool. Maybe it'd be nice to try that here.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Re: TDD, I love you

Post by Jenk »

My self, Chris and Spacegoat did that a while back with a Request class. We took turns posting the next stage of test and development, and would review each others contributions. Online paired/group programming as it were.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: TDD, I love you

Post by Chris Corbyn »

I'd be happy to run another of those walkthroughs :) If we can come up with a small idea for a project which would be of some manageable size to write code her on the forum then it'd be a fun way to get some people involved :) Nothing too big obviously; but I'd say if we choose something too small then it simply will not rub-off on the people involved very well (using a powerful tool to do something simple always convinces you it's pointless).

Maybe we could go with a form validator, with an imaginary framework that has a Request interface of:

Code: Select all

interface Http_Request {
  
  const POST = 0x01;
  const GET = 0x10;
  
  /**
   * @return int
   * @see POST, GET
   */
  public function getMethod();
  
  /**
    * @param string $key
    * @return boolean
    */
  public function has($key);
  
  /**
    * @param string $key
    * @return mixed
    */
  public function get($key);
  
}
EDIT | I'm not saying we should use my suggestion -- I was merely making *a* suggestion ;) We should also make a new thread when/if we do come up with a decent idea.
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Re: TDD, I love you

Post by matthijs »

It'd be a great thing to do.

Not sure if I would find form validation that interesting, as I think it's already pretty well-covered, with lots of examples using strategy patterns etc. But that's me, I can't speak for others of course.

Some other ideas might be:
- A model class. Not the traditional model class with a limited set of methods and data fields, but more flexible. Think Flickr-like tag data, gmail-like label data or the gallery tag idea from Onion2k (see here). I had some ideas and started writing them down but it got too long to post here so I'll keep it short for now.
- Import/export classes. In many webapps nowadays with user generated data it's important to be able to exchange data. It's also important that users can easily export their data in different formats (.cvs, .txt, etc). So you could start simple with a limited set of datafields and one format and then expand that and see what happens.

Whatever subject is chosen I'd find it interesting. These are a just few ideas I have.
Post Reply