Cyclomatic Complexity for the Test Driven PHP'er

June 5, 2006

It's one of the most common questions you ask when you first start using Test Driven Development or Unit Testing in general... When am I done? :)

It's the point you feel confident when all your tests exercise the code in your classes. How do I know when that point is? I've come across a new way of finding this point using something called cyclomatic complexity. Developed by Thomas McCabe in the 70's cyclomatic complexity is a simple measurement of how complex a piece of code is. One of the nice parts of it is that you can use it when working with unit tests.

Here is a basic example:
  1.  
  2. function getUserName($name)
  3. {
  4. $our_name = strtoupper($name);
  5. return $our_name;
  6. }


This method would have a CC (cyclomatic complexity) of 1. It's 1 because there is only one path the code can travel. CC numbers deal with how many paths it takes to get through your method. So each time you use an if, case, ternary, etc conditional statement you add 1 to your CC score because you're adding another path the code could flow through. Let's show the same example with a CC score of 2.

  1.  
  2. function getUserName($name)
  3. {
  4. if($name != '') {
  5. $our_name = strtoupper($name);
  6. return $our_name;
  7. }
  8. }


We added one conditional if statement which now means we have to write at least 2 unit tests for this method now. While you were writing your second unit test for this method you'd quickly find out that if the name is blank there is no code to handle that and the function would return nothing. Not expected behavior from this method. So using CC numbers you can help find that time when you can safely say you're done unit testing this piece of code. When you have tests that exercise each branch of the CC number which should give you a code coverage number of 100% when you're done.

The other nice part of a CC number is you can quickly find out when a method is ripe for refactoring. If you have a method with a CC number of 20 you know you most likely have a problem on your hand. This means you'd have to write 20 unit tests just to cover the basic funcitonality of that method. That means you have 20 if, else's, case statements which tend to make code brittle and complex. By refactoring these methods into smaller classes with the strategy pattern or using one of Fowlers refactoring methods you can work to make your code more flexible, less complex and more completely tested.

I'm currently working on a code metrics script that will include a CC number and point out possible issues with high complexity methods. Enjoy





Comments

RSS feed for comments on this post.

  1. Dennis Pallett says:
    June 5, 2006 @ 11:47 — Reply

    If you have 20 if, else statements your CC number could be even higher. The following example demonstrates this: function test($var, $second_var) { $result = ''; if ($var == 'one') { $result = '1'; } if ($second_var = 'two') { $result .= '2'; } return $result; } Only two if, else statements, but it will has a CC number of 4 (since there are 4 paths). I believe the latest version of PHPUnit has a Code Coverage tool which will automatically check if all your code is covered by your unit tests. Looked pretty interesting when I read about it a while ago (sorry, haven't got a link for it).

  2. Ryan Platte says:
    June 6, 2006 @ 15:30 — Reply

    Hi Jim, TDD guy coming out of the woodwork... Following the rule that code must only be written against a failing test (test-first programming) pushes CC way down, because you feel the pain of the increased complexity right away in decreased testability. Is it easier to write the extra tests or simply bust out a new method for the additional complexity? Testing first exposes that issue right away, while testing after leads to unfixed hard-to-test complexity.

  3. Jim Plush says:
    June 6, 2006 @ 15:35 — Reply

    hey Ryan, yep I completely agree. I hate writing unit tests after the fact but some times when you're maintaining someone else's code you have no choice :( I agree though if you were TDD'ing you would avoid high CC's at all costs or you'd never get anything done :)

  4. Rob Baillie says:
    December 12, 2006 @ 04:19 — Reply

    Of course, well modularised code leads to functions / method with a low cyclomatic complexity. The big question is though... Jim... did you get anywhere with your script... I'd be VERY interested to see it!

  5. Anonymous says:
    April 14, 2010 @ 20:22 — Reply

    Comment pending moderation

  6. blu ray ripper says:
    April 18, 2010 @ 04:11 — Reply

    Comment pending moderation

  7. HP0-J33 says:
    May 19, 2010 @ 00:50 — Reply

    Comment pending moderation

  8. virbram five fingers says:
    June 4, 2010 @ 20:29 — Reply

    Comment pending moderation

  9. LOuIs VuItToN Damier Graphite Canvas says:
    June 9, 2010 @ 21:14 — Reply

    Comment pending moderation

  10. silicone rubber says:
    June 11, 2010 @ 20:31 — Reply

    Comment pending moderation

  11. HP0-D05 says:
    June 12, 2010 @ 18:02 — Reply

    Comment pending moderation

  12. air force 1 says:
    June 15, 2010 @ 00:23 — Reply

    Comment pending moderation

  13. Louis Vuitton handbags says:
    June 16, 2010 @ 01:31 — Reply

    Comment pending moderation

  14. louis vuitton replica says:
    June 21, 2010 @ 00:04 — Reply

    Comment pending moderation

  15. replicas watches says:
    June 22, 2010 @ 00:05 — Reply

    Comment pending moderation

  16. air max says:
    June 24, 2010 @ 02:04 — Reply

    Comment pending moderation

  17. Knock Off Designer Handbags says:
    June 25, 2010 @ 21:35 — Reply

    Comment pending moderation

Leave a Comment

Line and paragraph breaks automatic, HTML allowed: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <code> <em> <i> <strike> <strong>

Comments disabled due to spammers being losers that lead sad lives.