DEV Community

Discussion on: What made you interested in learning how to write tests or how to TDD?

Collapse
 
imforja profile image
João Forja 💭

Hi, those are some great questions!

Depending on who you ask, you'll get different answers, as different people find different ways to integrate the general ideas of TDD into their workflow.

Therefore, in my opinion, the right mindset when learning TDD is not to try to find the one right way to do it, as if we were a computer executing a program, but to specialize the general ideas to our needs and context.

In other words, use TDD in the way that you find it makes you more productive, given the environment you're programming in. And by productive I mean reduces the number of bugs you produce and makes you go faster in the mid to long term.

With the above said, I'll answer the questions given my understanding and what has been working for me.

"What I am looking for is more towards the thought process when doing TDD."

In essence, I see TDD as a technique to bring clarity. Human language is fuzzy by nature. So when we're discussing requirements, there's a lot of room for misinterpretations. TDD gets mostly rid of misunderstandings by introducing verifiable hypotheses (tests). By turning requirements into tests, usually through examples of how something will work, we have a way of knowing if we're confirming to what's being asked of us.

NOTE: Depending on where you use the logic above (code level or client level), people will give them different names. When we're using tests to clarify what a client wants, people tend to call it BDD or ATDD. When using them to clarify what a code module should do, people call it TDD.

What's first on my mind when I'm using TDD is what do I need to clarify about this module that I'm building. I mainly look at the inputs of a module (parameters, dependencies, etc.), fiddle with them, and see if I can find a combination that I don't know what output it should produce. If that happens, I'll discuss with the team and look at the system's goals as a whole to determine what that module should do.

Eventually, I'll get to a point where the tests leave no room for doubts about what the module should do, and all that's left is to implement what's missing to make the tests pass.

"When it comes to TDD, do I think of writing tests for a feature or do I design the functions and write tests for it? The difference is that for the first one, my functions are derived from my test which could be further broken down into smaller units. Whereas the second one is more towards knowing what functions(no implementation yet) I will need for the feature and creating a test for each function."

We start at the client level (ATDD/BDD). At that level, we clarify what the client wants the feature to do through tests. These are usually called acceptance level tests since we're testing what we'll be building against what the client intends the feature to do.

After we have acceptance tests, we start to design what modules our system needs to have and what they should do to fulfill the acceptance tests.

NOTE: A module is not necessarily one function. Could be many, could be one, could be one with many inside. It can not even be a function. It could be a class, for example. It's better to think of a module as a code-unit with a job.

After we have an idea of the system's modules, we start to TDD against the interfaces of the module we came up with through the acceptance tests.

So to answer the question more directly, we start with acceptance tests. From there, we come up with a general idea of the structure we'll need to make the tests pass. By structure, I mean modules and how they interact. At this point, you'll probably already have an idea for the signature of the modules' interfaces. Now you write tests against the modules' interfaces to verify they work as expected.

"What does it mean that TDD is more of a design than testing?"

When you're using TDD, you're forced to be a client of your own modules. If the modules are hard to use, you'll start to experience pain when writing tests. That pain will force you to take a step back and look at the program's design as a whole and change it so that testing becomes less painful.

The general idea is that painful testing equates to a failure in some characteristics of what good design should be. For example, modules that are hard to test tend to have interfaces that are complicated to use. That complication will then propagate to other modules that use the complicated module. This gives rise to complicated interactions all over the program. And in a good design, it should be simple to understand how the parts interact.

NOTE: Although TDD can help with design, please don't get the idea that by using it, design considerations take care of themselves. We're the ones in the driver's seat, not TDD. If we don't study design, we won't know how to interpret the queues given by TDD or even if we should listen o them given the project's broader goals.

I hope this helps, and let me know if you have more questions :)