DEV Community

Cover image for Unlock the Potential of Test Driven Development: Strategies to Ensure Code Quality and Confidence
Melchor Tatlonghari
Melchor Tatlonghari

Posted on • Updated on

Unlock the Potential of Test Driven Development: Strategies to Ensure Code Quality and Confidence

  • Beyonce rule - "if you like it put a CI test on it" - Software Engineering at Google (O'Reilly)

Test Driven Development (TDD) is a development process in which tests are written before the code is written. It's based on the idea of "test first, code later". The goal of TDD is to help developers write better code and have greater confidence in its correctness. However, there are some common misconceptions about TDD that can lead to problems.

One misconception is that increasing the percentage of tests coverage should be the driving force for writing tests. While it’s important to ensure that all parts of your code are tested, focusing only on the percentage of tests coverage will not always lead to good tests. This approach is akin to addressing the effect rather than cause.

How to know if tests are good

Tests you write should give you confidence in the code

To know if your test is correct, you need to be sure that it is giving you the confidence that your code is working as expected. If a test does not pass, it should be a sign that something is wrong and needs to be fixed. A successful test should give you the confidence that your code is working correctly.

Tests breaking should give you a sigh of relief rather than a sense of dread

When a test breaks, this should be seen as an opportunity to find and fix any issues in your code. It should not be seen as an obstacle or something that needs to be done manually each time. Instead, tests should be part of the automated development workflow so they can be run with each iteration of coding to ensure everything is working correctly.

Tests should be consistently passing or failing.

  • 1 % flakiness diminishes confidence in test suite, a workaround is retry flakey test programmatically if it cant be avoided. must be address though. - Software Engineering at Google (O'Reilly)

Tests need to remain consistent so they can accurately determine whether or not the code works as expected. If a test passes one time but fails another, then it cannot provide reliable feedback on whether or not the code works correctly. Therefore, tests must remain consistent so they can consistently provide accurate feedback on the functioning of the code.

Flakey tests are the fastest way to lose confidence in TDD. A flakey test is one which produces inconsistent results; one time a test may pass and another time it may fail for no obvious reason. This makes them unreliable and will quickly cause developers to lose confidence in TDD itself due to their inability to provide accurate results consistently across multiple runs of testing. Flakey tests should be either fixed immediately or deleted entirely.

Tests should be done automatically as part of the development workflow

  • Automated testing should be done as part of the development workflow for a number of reasons. It can help to reduce the amount of time spent on manual testing, making the process more efficient. Automated testing also helps to ensure consistency in quality assurance by running tests on multiple platforms at once, reducing the chance for human error.

  • By automating these tests, developers can have confidence that their work is being thoroughly tested without having to consciously spend time on it. This makes development faster and more reliable while also freeing up developers' time to focus on more important tasks.

Different Approaches to Testing

DOM Testing

  • The more your tests resemble the way your software is used, the more confidence they can give you. - Kent C. Dodds

DOM_TESTING

Suggested Reading on guiding principles of React Testing Libraries: https://testing-library.com/docs/guiding-principles

Sample Use Case:

One example of testing holistically is in a profile page. Here, testers must ensure that the user’s name, picture, and other details are always present. More Importantly, they must verify that when submitting details on this page, the changes made will be reflected in the output.

Approach

DOM Testing - querying the rendered elements of the DOM in order to make assertions about their text content, attributes, and key logic of the page. It is critical to test logic rather than just seeing if it certain components has been loaded, for example: If the user fills and the first name and clicks submit does the page expect it to be redirected or show an error that other attributes must be present.

Why is it good

Testing this way is good because it doesn't matter if another engineer changes the size, location, or color of the button or any other aesthetics. This test focuses on the core functionality of the page and makes sure those remain working correctly. This covers testing UI and implicitly state changes, which provides more confidence to your code than testing one or the either in isolation.

When it should break

The tests should break if an engineer changes a core functionality or removes any critical buttons from the page. In this case, an alarm should sound indicating that something was expected to be present but isn't.

Random Testing

Random testing is an effective and efficient way to ensure that your code is being thoroughly tested. Randomizing input and asserting the output helps to cover a wide range of scenarios and results, ensuring that the code is functioning as expected. When using random testing, it is important to consider when it should be used and what potential pitfalls may arise.

random-testing

When to use

Random testing should be used when you are unable to cover all possible scenarios in your assertions. This helps you cover a wider range of results and make sure that your code is functioning correctly. Additionally, it is important to have an automated run in place in order for random testing to be effective.

Pitfalls

One potential pitfall of random testing is that it can be disguised as a flakey test if it suddenly breaks. Therefore, engineers must take the time to review any unexpected failures rather than simply rerunning the test in hopes of getting a better outcome. Additionally, engineers may not have a culture of fixing unrelated failures to their commit which can lead to further issues down the line.

Asserting outputs from the start

One good way to ensure that your code is functioning properly is to assert outputs from the start. Asserting outputs from the start involves writing tests which check for the expected output of a given function before the function has been written.

When to use

This method should be used if you are certain about what the output of a specific function will be before having written it. Additionally, this type of testing can be beneficial in putting guard rails around functions which may not have obvious outcomes.

Why is it good

So why is asserting outputs from the start a good practice? For one, it acts as documentation for future engineers who may be building on or modifying your code. Additionally, it gives you an opportunity to test different kinds of inputs and assert outputs based on how you expect your function to work. This helps ensure that any assumptions you have about how your code will behave are correct.

Conclusion

Test Driven Development is an effective way to ensure code accuracy and quality. TDD works by writing tests before code is written and testing the output of code before it is written. However, there are some common misconceptions about TDD which can lead to problems if not addressed. By using good approaches such as DOM Testing, Random Testing and Asserting outputs from the start, developers can have greater confidence in the correctness of their code. With these techniques in place, developers can have peace of mind that their code is accurate and reliable.

Top comments (2)

 
mel3kings profile image
Melchor Tatlonghari

Sorry, I might not have been clear on the article and will make it clearer next time but when I mentioned DOM testing, it wasn't mostly checking if DOM exist but testing holistically about state changes. e.g.: if you click on submit how does the state change does it show "Successfully Submitted" or "Error", in that way it implicitly test state changes via testing UI. It covers both UI and state changes, which provides more confidence to your code than testing one or the either in isolation.

Collapse
 
mel3kings profile image
Melchor Tatlonghari

I beg to differ, the main principle of react testing library:

"We try to only expose methods and utilities that encourage you to write tests that closely resemble how your web pages are used." testing-library.com/docs/guiding-p...

This helps application behaves correct pre-commit.