Testing your code

by Mads Kristensen 9. July 2007 21:42

I was asked to write a post about my views on unit testing because it is a hot subject at the moment.

I’m very ambivalent about unit testing and always have been for many different reasons. Although testing is very important, I often find unit testing to be a time consuming liability but it depends on the project.

Good for static classes

Over the years I’ve build many helper class libraries which is used in many projects and can be considered as business independent fundamental classes. All the classes in those libraries are static and therefore cannot be considered to be entities, but merely a logical placeholder for static methods that works independently.

To unit test such libraries is a must have. They are simple to write and maintain and unit testing is important because the libraries are used in a vast amount of different projects.

Object orientation and business entities

A unit is the smallest testable part of an application which means that for object orientated applications/libraries it will always be a class or business entity. Of course you can test the individual methods, functions and constructors but it doesn’t make much sense since the business entity is to be considered as a single unit and also works as such in real scenarios.

For me it makes more sense to conduct use-case testing on business entities. It works much like unit testing, but is constructed so they test a complete flow of operations on the class. For instance, if I had a class called Dog, then I would write a use-case test that simulated how a real person would use the class. First Feed the Dog, then Pet it and then Walk it before it needs to Sleep.

For that purpose it doesn’t really matter if you use unit testing frameworks such as xUnit or write it in a console application in the same Visual Studio solution. I like both approaches equally, but most often write a console application because I find it simpler.

Never-fail-applications

Financial applications used by banks or government applications needs to be tested extremely well. Those types of applications deal with people’s personal data and money and must never ever fail. The same goes for applications that ships on CD's or DVD's unless they are updated automatically over the Internet.

There needs to be automatic tests running every day and both unit testing and use-case testing is very important. The 80/20 rule does not apply here; it needs to be as close to 100% code coverage as possible and each class needs to be use-case tested for dozens of scenarios.

To test this properly you need professional testers and QA’s because the test is as important as the application itself.

What about no test

The most common thing is to have no test but the application itself. Admit it; you do this all the time as well. Is it a dumb idea to use the application to test its dependent libraries and itself and not doing unit or use-case testing? No it definitely is not. The end user application/website is the ultimate test, but there is a serious problem with not having an automated test harness. If an error occurs you can spend more time finding the problem than it takes to fix it. For smaller projects though, I find it perfectly acceptable to test from the GUI without a test harness.

Also, it is very difficult to test GUI’s automatically so it will be a good idea in most cases to use a test harness for every project in the application stack and then create a procedure for testing the actual GUI. In most cases it has to be done by humans manually.

Test driven development

TDD is one of the hyped methodologies that I never really understood. I can’t get my head around writing the test before the class it tests. In C# it doesn’t make sense to me, because if I write a test to call a non-existing class and its methods and properties, then it will not compile. Then when I write the actual class I often compile to check for errors. That doesn’t work either, because the test references some methods I haven’t written yet and as so cannot compile.

Besides, in most cases I don’t know 100% what properties and methods the class needs and which of them is public or private. Then I need to get back and change the test and thereby looses the point of writing the test before the class.

User driven development

For smaller projects with few dependencies user driven development is for me the best way to test. Consider a rather small project like BlogEngine.NET with one web project and one class library. The class library is only used by the web project and nowhere else. That means that the class library has no classes, methods or properties that is not used by the web project so by testing the web project, the class library get’s 100% code coverage.

If a new feature needs to be implemented in both the web project and class library I use the web project to test the class library. That’s because I’m as much a user as a developer of the project. If you are not the end user, then you should test as much as you can on the web project and then get a co-worker or the customer to test when you feel confident it works. It’s always a good idea to let the customer test as early in the process as possible.

Simple code is simple to test

If you always make sure your code is simple, clean and refactored, then testing is equally simple to write. Complex code needs complex testing and the maintenance of the tests will increase with every change to the code. Every time you change a little thing, you need to rewrite many tests if your code is complex. That goes for both unit testing and use-case testing.

Conclusion

I find unit testing to be good for very few types of projects – helper class libraries and never-fail-applications. User driven development with use-case testing is my absolute favourite. I don’t see the big difference in using a xUnit framework or using a console application, because you only get the benefit from a test project when something fails. For automatic testing though, you need a testing framework that logs the results.

This is how I would manually test different projects.

  • Helper class libraries – unit testing in xUnit or console by the 80/20 rule
  • Never-fail-applications – automatic unit and use-case testing written by QA’s. Full coverage
  • GUI’s – test yourself, then a co-worker and then let the customer test
  • Business object layer – use-case testing in xUnit or console by the 80/20 rule
  • Data access layer – unit test in xUnit by the 80/20 rule

Again, it is very important to note that it all depends on the type and size of the project. If you don’t have a build- or versioning server to handle automatic unit testing, then you have to do it manually. If you have the ability to automate unit testing, a xUnit framework is the way to go but full code coverage is not always necessary and not all projects need unit testing.

* Only $4.95/month ASP.NET & Windows 2008 + IIS 7 Hosting! FREE SQL Included

Tags: , , ,

General

Comments

7/9/2007 10:13:01 PM #

Josh Stodola

Welcome back, Mads!  Great post, I like your approach.  Simple code is simple to test... that says it all!

Josh Stodola United States |

7/9/2007 11:21:21 PM #

trackback

Trackback from DotNetKicks.com

Testing your code

DotNetKicks.com |

7/10/2007 2:05:15 PM #

TweeZz

Hi Mads,

Thx for your post. A few questions though..
- What's the 80/20 rule?
- According to what you wrote, you would write unit tests for every method in the subsonic 'sugar'? subsonicproject.googlecode.com/.../
- Could you maybe give some concrete real life example(s) of the use-case testing on business entities?

Maybe somehow connected with BlogEngine. That way more people could learn something from it..

How much do you charge for private lessons? Laughing

TweeZz |

7/10/2007 7:34:32 PM #

DavidMiles

Nice to see you back - good post - I am assuming the 80/20 rule is the one that states "that developers spend 80% of their time debugging applications and 20% writing new code" ...

DavidMiles United Kingdom |

7/10/2007 8:50:18 PM #

Mads Kristensen

The 80/20 rule says that you get 80% of the features for 20% of the work

Mads Kristensen Denmark |

7/10/2007 11:02:29 PM #

matt

But that's the point of TDD, using testing to determine functionality. It's not always applicable, and it can at times be difficult to know what a class needs to do before its written. But often, in those cases, that's also a sign of poor or too complex design.

It's ok that your code doesn't compile at first in TDD, that's really just an artifact of C# being a compiled language (or that no C# IDE does background compiling). The real benefit here is the test has determined exactly what the class needs to accomplish (a failing compiler is just the predecessor to failing tests. They both just say "the class doesn't meet its contract yet"). Once the tests are written, often writing the class itself is very simple, all the guesswork has been removed and a contract (the tests themselves) determine exactly what the class must do. Nothing more or less. It typically leads to writing only the code that is needed, components that are loosely coupled, and best of all, components that have very high test coverage.

TDD is weird at first, but once you grasp it, it's great.

matt United States |

7/10/2007 11:32:58 PM #

Chris

uh-oh, looks like a "user test"(me) failed on blogengine.net,

"There is an unclosed literal string. Line 1, position 705."

Chris United States |

7/11/2007 1:21:40 AM #

trackback

Trackback from roy ashbrook

re: Testing your code

roy ashbrook |

7/11/2007 2:38:16 AM #

Dan

Wow killer post, a pragmatic vision of the new religion in software development, unit testing.
I do unit testing and I totally agree some points:

Testing existed before xUnit frameworks, if a console app or an asp.net website is the best way to test a utility class then do it ! The tests make the job, are repeteable and so on.

About writing the tests before the real program, I believe this is more a design technique but working software can be written without doing that. And BlogEngine.net is a good example, it has been created in a few weeks, works great and is more easily extensible than others thanks to intuitive design.

So the result is the expected, and this is the goal of a developer, create working software. Sometimes with the help of xUnit and mock frameworks, and sometimes without them.

Testable designs are not the more intuitive, with plenty of interfaces, public classes with virtual methods, absence of static members, constructors only created for testing and the use of dependency injection around the code.
It's difficult for a few experienced coder to search where are injected the logging, authentication, HttpContext mock/dummy object and data providers. And probably that coder want to extend the blog engine with some cool idea and then he breaks the testable design calling Page.Trace.Write

Different software have different objectives, there is not a golden rule for how to create it. The common sense must guide us to get our goal.

Dan Spain |

7/11/2007 2:48:45 AM #

Mads Kristensen

Dan, we agree Smile

Mads Kristensen Denmark |

7/11/2007 3:16:39 PM #

Adron

Heya...

I'd love to see what you write after working a project with TDD and people who have serious experience developing with it.  Doing a hard core Agile project, eXtreme even, and then returning to non-TDD, non-Agile development seems like things have been cast in blocks of cement.  Regular projects just don't move forward compared to TDD/Agile/eXtreme projects.

Give it a whirl, I'd put money on it you'd change your song.  Smile

Adron United States |

7/11/2007 7:10:53 PM #

David

I'd agree with matt - the point about TDD is that you define the functionality by the tests. It not only keeps you focused, but also addresses the YAGNI issue.
I didn't really grok Test First development until I read Kent Beck's book. I'd highly recommend it - it only takes a couple of hours to read, and I felt like a light had been turned on in my head.
[also, http://en.wikipedia.org/wiki/You_Ain't_Gonna_Need_It doesn't link properly!]

David United Kingdom |

7/11/2007 8:50:14 PM #

alien

Hey,

I worked for more than a year in a hard core Agile environment, with TDD, 100% test coverage.

Concerning agile itself and project speed, it's just a matter of good team leaders and project managers - they have to motivate people. If they're good and hire responsible developers, you don't need agile methodology to create prototypes and develop at high speed (that's my current company and they don't use Agile).

I can imagine that TDD might be usable in some cases, but I don't use it any more. It definitely slows you down and adds some maintenance overhead (i've got some exeperience with that).
If you know how to design code, you don't need TDD. If you don't know how to design, TDD doesn't help you and then you get bad code with bad tests...

My biggest issue with TDD is that I usually wrote a couple of tests (which were failing at the beginning), then I implemented the appropriate code and then I realized that the tests were still failing cause there were bugs in them (in fact it was completely useless to write the tests first). It just doesn't work that way.

IMO it's just a matter of "religion", to use Agile methodology.

My current approach is to design code using UML and design patterns then to implement the functionality (everything must be self-descriptive) and then some unit tests (if needed).

alien Ireland |

7/15/2007 7:29:41 AM #

Adron

Actually "it's just a matter of good team leaders and project managers" I have to agree with totally.

It helps when methodologies flow with the habits of good team leaders and project managers tough.  When it does then things go really really well.

I have a blog entry coming up on this topic soon!  Smile

Adron United States |

7/26/2007 1:05:16 AM #

pingback

Pingback from seregaborzov.wordpress.com

Сделай код проще… « Блог Серёжи Борзова

seregaborzov.wordpress.com |

Comments are closed

About the slave

Mads Kristensen Mads Kristensen
Web developer at ZYB and founder of BlogEngine.NET. More...

LinkedIn ZYB Facebook Last.fm Twitter View Mads Kristensen's profile on Technorati

The Lounge

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008