The Fearless and Natural Approach to TDD

I’ve been applying TDD (Test Driven Development) religiously for the past 5 years and now cannot imagine where I would even start from, in any code if it’s not from a test. The advantages TDD brought along with it are numerous and in my case, vital, for working on projects of a certain calibre. Even though the complexity of any code is now irrelevant to me when it comes to TDD as I always apply it. In a form or another, every code I write follows a test I’ve written.

This post is not a tutorial of either Unit Testing nor PhpUnit. The main purpose is to help you adjust your mindset in a way that facilitates TDD. I will do this by highlighting the issues I experienced myself when thinking tests firsts and then I will continue on this series of posts -Developing a Command Bus in PHP with developing some initial features using the TDD approach, to hopefully walk you through how the mindset evolves for TDD to become a natural and obvious way to drive code development.

What is Test Driven Development? A shift in Mindset

Sounds simple right? Well, for me, it wasn’t, at least not at first. I couldn’t make this work in my head. I’ve been exposed to TDD well before the last five years but in all honesty, it always seemed like too much work to learn a testing framework and to install this and that. The reality was that these fears, stopping me from implementing a TDD approach to my work were the easiest to conquer. Learning how to use a new framework such as PHPUnit is extremely easy for most developers. We learn new frameworks every year, not to mention new languages and standards. I was in a point in my career where I was being given opportunities to work for large-scale companies on large-scale projects. I had to make TDD work because the cost of not having automated testing was way too high. I remember this moment in detail because it was, this, a milestone in my software development confidence. I spent all my free time for a week, just writing tests for dummy problems. I learned PHPUnit and I could write tests. But the penny hadn’t dropped yet. I still couldn’t think what to test for and thus how.

The issue I had with the TDD mindset was not with the tests directly but more in breaking down features into adequate units of work. I say “adequate” because it did take me a few attempts at establishing an informal policy of what makes a unit. Units are very easy to test because normally (in SOLID code), they correspond to one method or one public method and a subset of helper internal ones, clear and concise.

Eventually, the penny dropped and everything made sense. The results were immediate. The gain was imminent, from the first project up till now. I reduced the number of post-release bugs to almost zero in most of the applications and I reduced the actual working time by around 40%. This means I gain better opportunities to work on projects with smaller budgets without affecting the quality of the code.

When we think about what something should do, given it is independent of other “somethings”, we can easily establish what to test for by checking if that thing was done. We can also, as easily test what it shouldn’t do.

What is Unit Testing in TDD?

Think about the required feature as to what is the expected result. Then break it down into doable things (units of work) and then test for each thing (unit) one by one. Rinse and repeat.

Remember that there are other types of tests such as Integration Tests which may be formed of several units of work, however, I would say that in this case, the Unit is the actual Integration under test. This may be debatable, so I’ll look forward to your comments 😊

TDD in PHP

Once again, It's important to note that TDD does not necessarily imply unit testing. TDD can be applied to several layers of an application; units, functional, features, behaviours and integrations. It also does not have to be automated, although it does help :)

The most popular testing framework in PHP is PhpUnit. I don't think this statement is debatable but do let me know in the comments below if you disagree. I will not use this article as a PHPUnit tutorial because there's plenty of them out there, one in particular that I enjoyed a while ago is this one . Not to mention that Sebastian Bergmann himself did a very good job in documenting the framework all over the world wide web and offline.

Instead, I'll continue expanding on our Command Bus composer package example from the previous posts to illustrate this new natural and most probably obvious mindset. The same way I learned to TDD every day.

TDD example with PHPUnit

In the previous post PHP Software Development Workflow of this series, we've set up the project and tools. We also already added the PHPUnit dependency to our composer.json file. This goes to show my mindset :) In this post, I'm not going to go into any detail about setting PHPUnit up or even how to use assertions and mocks etc... I simply want us to take a couple of features we need to develop and apply a TDD approach to these requirements. However, as always, please do get in touch whenever you wish for me to elaborate on any detail. I really enjoy answering your questions and it's becoming a daily habit now :)

Let's get to it, shall we

Our Command Bus component needs a Resolver class to resolve the CommandHandler of the Command and resolve the dependencies a Handler may have such as a Repository or a Specification object. Initially, a resolver will do all this from a provided array, however, we may wish to automatically resolve dependencies when we have an Application Container such as when we use frameworks like Symfony or Laravel. Therefore, for now, I'll start with specifying an interface for a generic Resolver like so:

The above interface will be implemented by any concrete CommandHandlerResolver like our one today, the ArrayResolver or in the future, a LaravelResolver. In order to define or establish our units of work we must start with listing the desired functionality, which may become our units of work or a group thereof. What I'd like our Resolver to do is to take an array of Commands and their Handlers. If the Handler has any dependencies, then we pass an array of instantiated dependencies. In the future, other resolver implementations may also resolve bounded interfaces etc.. but for now, we'll just focus on the concrete ArrayResolver.

The first requirement is the ability to retrieve a CommandHandler for a given Command. I'll start by writing an extensible TestCase to avoid having to bootstrap the dependencies in every test:

namespaceSwellPhp\Admiral\Test;useSwellPhp\Admiral\ArrayResolver;.../**
* Tests for the array resolver.
*
*/classArrayResolverTestextendsTestCase{/**
* Tests that it can get the command handler for a given command.
*
* @test
*/publicfunctionit_can_get_command_handler_of_command(){$handler=$this->resolver->getHandler(newDraftNewBlogPost('title','content'));$this->assertInstanceOf(
\SwellPhp\Admiral\Example\Handler\DraftNewBlogPost::class,$handler);}}

Needless to say, this test will fail because we don't have any code written, so I'll go ahead and write the code which will make this test pass, hopefully, but if not, we know exactly which part of our software needs to be worked on. The elegance of knowing 😉

Well that was easy, wasn't it? Next, let's think about what can go wrong with the getHandler() method. Okay, so, what if the Command was not added to the array and thus is not registered. We'll develop an exception class CommandNotRegistered and write a test which expects this exception to be thrown. I developed the exception class first so that I could reference it in the test. This is simply an Exception class:

I'd like to point out that there are several other ways to achieve the same results in PHPUnit, I opted to use dummy classes for testing because they are better in explaining the process and even more important, they expand on this mindset through clear expectations.

The point here is to first break down the task into small and well-understood units of work, then write a test for the desired result and write the code to make the test pass. Following this, think about what can go wrong, what are the exceptions (exceptions in desired outcome or expected input) and test against them. Please also note that these scenarios are not specifically tied to exceptions. They can be varying business rules and specifications among other conditions.

To keep this post from becoming a lot longer than it already is, I'll briefly illustrate another requirement, resolving the CommandHandler dependencies, but please note that even in this small example, I have actually tested for other scenarios, such as when CommandHandler class is not found.

Are you enjoying reading this article?

Subscribe to receive email notifications when I publish new articles and code libraries.

I will not share your email address with anyone, and you can unsubscribe at any time.View the privacy policy for more information.

Two main points here, one, you'll notice that I've actually really created a class ListOfPost. In practice, you can achieve this by using Mocks or even anonymous classes (as of PHP7) but I need these classes to exist for illustration purposes on here and also for future use in the documentation (2 birds one stone! I love animals and would never throw a stone to one unless it would save my life by doing so - even if I can hit two at the same time 😊 ). The second point is that in reality, we need to be able to resolve dependencies even when there are multiple ones. The Resolver does this and the code is included in the repository (linked below), however, while I was testing and developing along, I had some issues, so I broke this down to two more Units, one to resolve the dependency of a `CommandHandler requiring only a single dependency and then, once all my errors were resolved, I could move on to resolving multiple dependencies with ease. You'll find yourself doing this very often as it aids debugging and understanding the cause of an issue.

You can find all of this code and the related features on GitHub.com .

With the Resolver feature of our Command Bus component completed, we have seven tests and eleven assertions passing as shown in the screenshot below. I also included the broken down tasks I followed from start to finish of this feature to extend on the previous post about my PHP Software Development Workflow.

The famous green bar

Issue GH-3 completed.

TDD is an obvious choice

I hope that this article persuades all non-testers to convert to TDD and existing testers to challenge how my mind works and thinks. Test Driven Development is easy once we change our mindset. Unfortunately, there are still several companies which as much as I used to, still think that TDD is costly and not as important as its made out to be. This is definitely wrong in web application development and most other applications of software. The learning time-frame, when approached correctly, is only of one or two weeks and the benefits are immediate. Now go and tell your boss to read this article, the two weeks you'll spend learning TDD will be gained within the same project you're learning along. You will save more time straight away and if for any reason, you get stuck, then simply get in touch. I'll be happy to help.

Have you enjoyed reading this article?

Don't be selfish, share it with your friends 😉

Got questions or feedback? Leave a comment, I will reply.

Full-stack development

Need help?

Whether you need a solo developer or a team member, I can develop websites and applications from the backend model, to the application, infrastructure and front-end layers.

Latest articles

Laravel is an excellent framework for developing PHP applications. Whether you need to prototype a new idea, develop an MVP (Minimum Viable Product) or release a full-fledged enterprise system, Laravel facilitates all of the development tasks and workflows. How you deal with deploying the application is a different story. Vagrant is very good with setting up a local environment…

Getting started with Docker and Kubernetes on Windows can be daunting when you don't know where to begin.
And it doesn't help that installing the software isn't exactly a walk in the park.
In fact, you should already be a Docker and Kubernetes expert to navigate the options on how to install them. But don't worry! If you're just starting your journey with containers and…

I honestly feel obliged to write this article because I feel that most developers think about Event Sourcing as only another PoEAA (Pattern of Enterprise Application Architecture). Maybe reserved to software models which have a certain level of complexity or at least they need to look like they do so that the time and cost is justified. Event Sourcing is a lot more than just an…

Laravel is an excellent framework for developing PHP applications. Whether you need to prototype a new idea, develop an MVP (Minimum Viable Product) or release a full-fledged enterprise system, Laravel facilitates all of the development tasks and workflows. How you deal with…

Getting started with Docker and Kubernetes on Windows can be daunting when you don't know where to begin.
And it doesn't help that installing the software isn't exactly a walk in the park.
In fact, you should already be a Docker and Kubernetes expert to navigate the options on…

I honestly feel obliged to write this article because I feel that most developers think about Event Sourcing as only another PoEAA (Pattern of Enterprise Application Architecture). Maybe reserved to software models which have a certain level of complexity or at least they need to…