Unit Testing and test driven mentality



Please note, if the slides above do not show up, please use the direct link to them: PHP Unit Testing in Yii slides.

There are a couple of things I'd like to add to these slides since they've been done in June last year.

As you probably noticed, Yii has tried to make Test Driven Development as easy as possible.
Unit Testing will end up being a must if you want to have safe code deployed to production, improve your regression testing and provide a developer-friendly documentation for your libraries.

On the other end most of the people are worried about the time it would take them to write tests, and how testing should actually be done, how much you should test and so on...

Let's dig a bit into these issues.

Should you worry about code coverage?

While I was working for the Homepage of the BBC, we were trying to aim to the 100% code coverage of the whole codebase we had.

Unit Test all the things - meme

This led to a couple of considerations, which I later found out were echoed in several talks I've attended in the next years (specifically one given by Simon Stewart, lead QA at Google and main devel of Selenium).
In practice, you can't. And we did find that out the hard way.

In particular, dependencies are hard to test: legacy libraries and code you don't own might not have been created with testing in mind. Mocking code you don't own could end up being incredibly difficult and sometimes impossible without having to massively rewrite your code.

You might want to consider having integration tests, either being at a functional level or — if feasible — using specific unit tests (I'm not getting into the detail, but PHPUnit lets you use unit tests as integration tests).

There are also some people, and I'm amongst them, that suggest that while in a MVC environment, unit testing the Controller part is a ridiculous idea: mocking the whole browser environment is ridiculously expensive, practically impossible to replicate (think about cross-browser compatibility) and there are better approaches for that (i.e. behavioural and functional tests).

There are more important parts that need testing. As an example, think about data mining libraries, heavy computation bits of your code are definitely benefiting from unit testing. You might know that doing exploratory testing could potentially be time consuming, more than writing one test that covers some corner-cases.

What are the real benefits?

As you might have guessed there are several benefits in doing Unit Testing, especially if you embrace the Test Driven Development practice.

The hardest part everyone who starts writing unit tests has to face is the change in mentality. The way you'll write code will change, you won't be taking anymore what I would call a selfish approach. You'll start looking at your code from a third party perspective, which is making the code easier to be distributed, used and maintained by other people and yourself.

But as I said before, not everything is testable.

Writing tests is also a very good step forward to understanding what's the extent of what you're coding: you might have already experienced that some tasks could become some ever-growing multi-headed monstrous beast.

You need to have a quality assurance strategy in place.

Knowing what to test and what not to test, is of great benefit: you start seeing the whole picture and you start noticing what you're actually doing, how much you need to do and what could potentially be the hurdles you need to deal with. You also start seeing where the critical parts are: this will give you focus and determination on your project.

Should you really write tests first?

If you've heard anyone talking about TDD, you've also heard the mantra: Write tests first, then code.

Within a TDD team/project it's easy (well... mandatory, somehow) to stick to the rules. Harder is when you're working on your own or working in an environment that does not fully understand the extent and benefits of what you're doing.

Fear not fellow coder: your aim surely is writing tests first, but there's always a progression. And the progression comes always with the change of attitude. As I said before that's the hardest part. I'd like to suggest that iterating can come useful.

Sketch your tests, how you think the code should be used, then write down a quick draft of the code in question, then iterate to refine the test including corner cases, and so on.

This might have some eyebrows raised, but I've felt more than once that this is depicts an actual scenario.

You might not know where you end up placing your code and once you've finished writing the first draft of your tests, you'll soon discover that it's not feasible (because libraries, dependencies, etc) once you start implementing it. So I think that being less strict can be beneficial for our code and ourselves.

If you manage to overcome your attachments to a way of coding that does not belong to you and nor does define a good developer, you can start seeing the actual benefits of writing tests, writing them first and enjoying what you've done without fear of being judged.

Enjoy coding.