Test Driven Development is a coding practice where you write a test first then write the code to pass that test, usually in short iterative cycle.
Now let’s visualize TDD in steps:
- Write a test (enough to make it fail)
- Run it, and see it fail.
- Write the code.
- Run the test again and see it pass.
- Repeat Step 1
So now you can see that TDD is a closed loop process. A programmer is immersed into a flow that keeps him tied into the practice of either writing a test or writing the feature implementation code.
“So what are the benefits?” you may ask. There are several benefits to following a TDD approach.
- It helps keep the distance between what you know works and what doesn’t in your code very thin. You can pretty much figure out what went wrong, since you had the tests working perfectly a few seconds ago.
- It helps to minimize the time needed to refactor your code, since you can easily test if something breaks when you do refactor.
- It makes adding new features that much easy, since you can change code to accommodate new features very easily.
- It makes you confident as a programmer. You do not have to fear the code anymore. This is due to the above points 2 and 3. You can easily add new features and refactor your code without worry.
- It helps to break down software development into chunks that you can manage. So long gone are the fear of starting out on a new feature, since the TDD loop is short enough to easily get started.
- It helps to stop the exponential cost of change as the software grows, since you can add features without it taking more time.
In the talk Konstantin talks about the exponential increase in cost of change(adding new features) as project time goes on if there are no tests.
But if there are tests, the cost of change gets capped, making it much easier to add new features.
There are of course some disadvantages too.
- It is not easy to get started with TDD. It requires you to know a lot of new practices and techniques. Example: unit testing, mocks, assertions etc.
- It takes more time upfront when doing the development, since you are testing your code as you write.
One interesting series of debate is the Is TDD Dead? series by Martin Fowler, Kent Beck and David Heinemeier Hansson. David argues that TDD is not suitable for all types of coding styles. And argues that TDD has actually introduced more problems that it solves.
But all in all, I prefer TDD since it has much more upsides and very little downsides. I say, TDD is actually essential if you want to maintain your code base for a long time. If you are just experimenting with your code and do not need it for a longer term, you may not need TDD in that case.
So what does the Test Driven Development consist of? Well, there is the unit test that you write before you write most of any new code. Some of the code we write actually are tested with integration tests. So for code that interacts with third party API or library/database etc, we write integration tests instead of unit tests. Don’t worry, we will go through each type of tests in detail soon on the upcoming parts.
Let’s look at the different types of tests in brief:
- Unit Testing: Unit testing is the lowest level of testing you can do. It is usually testing a method inside a class. Unit tests do not interact with other classes directly, but instead with mocks. This makes unit tests isolated and easy to debug and refactor.
- Integration Testing: Integration testing touches more than one class. Hence, it tests the integration between classes i.e dependencies. It is used to test if the database is giving us the correct results, if an external API is providing us with correct data etc. It tests the real classes and functionalities rather than using mocks. It is significantly slower compared to unit tests to run, since they interact with databases and external providers.
- Functional Testing: Functional testing is testing a whole feature which may call a lot of dependencies. Typically you would test a route for a correct response, or a Controller method that relates to a certain feature in the application. They are slower than integration tests as they touch a lot more dependencies.
- Acceptance Testing: Acceptance testing is the highest level of testing. It only cares if the feature works through the vantage point of customers. The test flow goes through the website clicking and submitting forms and expecting correct results. We use tools like Selenium for this purpose.
In the next part we will go through how to setup PHPUnit and get started with unit testing. We will first do it without following TDD approach. This is because it will be hard to grasp both concepts while just starting to learn how to test. We will follow TDD once we are comfortable with writing tests. So we’ll save that for a later part. :)
Hope you enjoyed the article. Don’t forget to hit the 👏 icon below. And subscribe for more!