Test-Driven Development in an Agile world

Businesses focus more and more on Continues Integration and Continues Deployment in the Agile / DevOps world. The urge of businesses to update their software more often results in extra time pressure on testing the software.

In the Agile world, the road to the goal is mostly unknown. Test-Driven Development could be the lifeline you need.

Test-Driven Development could be the lifeline as an answer to this problem.

What is Test-Driven Development?

Test-Driven Development (TDD) is a development method that describes using use automated tests in the development phase. A big difference compared to classical development is that TDD forces you to write the tests first.

It might look like TDD is all about testing software, but this is not the final goal of this method. The goal of this method is to evolve the system to meet all its functional and non-functional requirements in an automated way.

Another term that is often mentioned is KISS. KISS stands for “Keep It Simple, Stupid”. A friendlier version is “Keep It Simple and Straightforward”. This principle describes that you spend as little effort as possible to solve the given problem (or challenge).

What does the method look like?

It’s best to have an initial Software Architecture to use the TDD method properly. I’m not talking about having a big design up front, but at least an architecture “on the back of an envelope”. This way the biggest design decisions and responsibilities are clear.

Determine what architectural decisions you have on testing also. In some cases, you don’t want to write unit tests, because it would decrease the quality level of the code or it’s just too complex. You can write automated scenarios or integration tests for these situations. The key is: automate all tests. In the following steps, I assume that the tests are unit tests.

The method contains the following steps:

  1. Determine the most logical test to write;
  2. Determine the test conditions;
  3. Write a skeleton class (just the method signatures) so the code can compile;
  4. Implement the test;
  5. Run the test (it should fail);
  6. Make the test work with the least amount of effort;
  7. Run all automated tests;
  8. Refactor the code;
  9. Run all automated tests again to determine that the software still works as expected;
  10. Repeat until the Product Backlog Item (User Story) meets the acceptance criteria

Step 1: Determine the most logical test to write

The first step is determining the first test to write. To do this you need to take dependencies into account. First, you need to implement the changes that you are depending on.

Step 2: Determine the test conditions

A unit test consists out of three parts. Arrange, Act and Assert. To make sure you implement only what’s needed, you need to know the pre and post conditions of the method you are going to implement.

Given the following User story:

As user, I want to schedule only non-conflicting appointments, so I don’t disappoint any of my customers.

The user only wants non-conflicting appointments in this user story. There are five different ways a new appointment can cause a conflict.

  • The start of the new appointment can be during an existing appointment;
  • The end of the new appointment can be during an existing appointment;
  • An existing appointment can start and end between the start and end of the new appointment;
  • The new appointment can start and end between the start and end of an existing appointment;
  • The new appointment can have a start and end that’s exactly the same as an existing appointment.

You need to check all these conditions during unit testing. Determine the expected result of the scheduling method also.

Step 3: Write a skeleton class (just the method signatures) so the code can compile

This is not a step in the official Test-Driven Development method. Doing so makes our life a lot easier, as we can use code completion :-).

In this step, you create the class (if it’s new) and create the method. It’s very tempting to code the functionality too, but that’s not allowed yet.

Step 4: Implement the test

OK, time to write the test. A proven way to write tests is by following the structure of Arrange, Act, Assert.

  1. Arrange: Setup the environment in your test (like mocks and test data) in such a way you can assert the method your testing.
  2. Act: Call the method!
  3. Assert: Check the results you got back. Check your mocks, etc.

Step 5: Run the test (it should fail)

Run the test you just created. The expected result is that the test fails. If it succeeds, you have work to do and have to go back to step 4.

Step 6: Make the test work with the least amount of effort

The time has come to do what you have waited for! Time to code! There is a catch though, you have to code with the least amount of effort needed to make the test pass.

In our case of the appointment scheduling; There is no test available yet that checks for false dates, that’s why you don’t implement that yet.

Step 7: Run all automated tests

Once you finished the code and the test passes, it’s time to run all automated tests again. New code shouldn’t break the build or make other tests fail.

If any other tests fail, do all the necessary work to make all tests pass once again.

Step 8: Refactor the code

After running all the automated tests (and all pass), another bit of coding should be done.

This time you should focus on codes quality. Check if the code is compliant to the coding guidelines or standards. Remove duplicate code, add comments on parts that are not clear enough. Also, add comments used to render documentation.

Another part you shouldn’t forget is to check if the solution is still the simplest one for the problem you tried to solve.

Step 9: Run all automated tests to determine the software is still working as expected

In this step, you run all the tests again to verify that all tests still pass after refactoring the code.

Do all the necessary work to make all tests pass again if any of them failed after the code refactoring.

Step 10: Repeat until the Product Backlog Item meets the acceptance criteria

In previous steps, you probably implemented one or multiple methods at once. In this step, you need to verify that you met all the acceptance criteria as specified in the Product Backlog Item or User Story.

If the item in case meets the acceptance criteria, you are done. If not, repeat all steps starting from step 1.

Liked what you read? Share this!