To test, or not to test? This is a cause of friction among developers. Opinion is divided on the efficacy and economy of running tests, which leads to testing being neglected. Some hold that testing is an important part of building products, while others maintain that testing just creates more work. This is a topic worth re-examining to see if testing is important for quality assurance. The TDD approach will be of specific interest.
What is testing?
A test is a process by which the actual code required for a product is determined to be sound, reliable, and bug-free. There any many different kinds of tests, and a development team should not neglect them for the reasons we will examine.
Possible tests include, but are not limited to: unit testing, acceptance tests, visual regression testing, accessibility testing, performance testing, end to end testing, integration testing, and cross-browser testing.
Regardless of which test a development team opts for, the test process has to be run using a specialized testing code in a controlled test environment.
What is testing code, and how is it run?
When developers go about working their way through a new test, they use specific test code in an environment configured for this purpose. This is to ascertain if the elements under consideration work as they should in real-life scenarios.
Test code is different from production code in that production code is what comprises the finished product. Test code can therefore be thought of as prototype code which is designed to verify if the entire application will, in fact, work as expected.
The testing environment must represent the scenarios in which the app will function. For this, development teams use a testing framework, such as Jest, which allows for the creation of a suitable environment that mirrors how the product should run, allowing developers to run tests.
If all of the above is completed correctly and the test code is sound, the same results should be given consistently across different browsers and machines.
Why developers avoid testing
There is a common perception that traditional testing, carrying out manual testing, or using automated tests is extra work for development teams, especially as it requires writing new code. The production code is seen as what the business owners are paying for, not tests that require extra coding and work. The demands for achieving a successful test are also time-consuming and can entail extra costs.
Developer complaints tend to fall into these broad categories:
Maintenance and variation of practice
Best practice standards within teams are not always adhered to and sometimes test files are shared between different teams further down the life span of a project. This can lead to different developers not understanding the reasoning behind the resulting tests, with attendant confusion and time wasted on asking colleagues for clarification. Establishing best practices within and across teams can often be a good remedy for such issues.
Poor time economy
Many elements of testing take time and are often contingent on teams communicating with each other about different components and finishing different parts of the process up to the deadline. This can cause tension if each testing team does not finish exactly on time.
Existing tests are often conducted on different browsers and machines to ensure that the code and logic are consistent and not dependent on specific frameworks. Code that runs with limited success across different browsers and machines, despite not having any changes, results in a flaky test. Such a failing test usually occurs when developers have not sufficiently liaised with each other.
While these complaints are well-founded, there are counter considerations as to why testing is worthwhile. Therefore, before considering these, it is useful to examine the most common approaches to testing.
Code first vs. test first and test-driven development (TDD)
The code first approach is where development teams initially develop the product code and later determine the appropriate test coverage and write tests to verify the code’s functionality.
The problem with this approach is that it encourages the developer to view writing tests, additional code, carrying out test runs, and reporting back on code coverage as just additional unnecessary work. This, however, is a false sense of security.
The web app runs with its product code, and the UI seems to have a reliable frontend code, so why invest extra time on cross browser testing and creating testing frameworks just to examine individual components?
Plotted over the long term, it is highly unlikely that code has been written error free, all the time, for every product. This means that many apps will inevitably be deficient. Business leaders and product owners don’t want their project to be one of these casualties, so they will likely insist on some minimal testing at the least.
Developers have to write testable code to start the process, and those tests might well reveal errors. This entails refactoring, that is, correcting the errors discovered. This approach to testing can be frustrating and discouraging, and can also encourage shortcuts, poor code quality, or a tendency to avoid attempting a test pass altogether.
In short, it makes sense to factor in testing at an earlier stage and maintain this as a standard practice.
Here, testing forms part of the foundation needed for writing the product code and building the app. By factoring in the tests as an initial step to configure a code base, business owners can be confident that the finished product will be functional and reliable. The popular test-driven development (TDD) approach also grows out of test first.
In this way, test first acts as a safety net against near-inevitable errors and the costs associated with fixing these.
Test first is carried out in specific stages:
- Developers determine concrete examples of the work required for a detailed specification and prepare a test suite based on them. A test case is then created which is designed to allow the code to pass tests prove that it works.
- The tests are conducted. At this stage, the developer expects the tests to fail. This is because the product code necessary for running the business logic does not yet exist.
- Developers then write the code required to pass the test. In this manner, the developer includes the criteria for a code’s own efficiency in the code itself. This enables the emergence of sound production code.
- Once again, the developer begins testing and the test suite is completed a second time. At this stage, if the code in step three sufficiently meets the business need of the unit, the tests should pass, yielding a valid production code. If this isn’t the case, the code needs further work.
The software engineer can therefore write production code as a consequence of the test itself. A successful test finds the engineering needs of the project.
Test-driven Development (TDD)
The TDD approach is one that is extremely similar to Test First, from the developer starting to write test cases to go through at least two rounds of testing.
First, a test is written that tests a specific business need or product scenario, and then the test fails as the code required has not yet been created. The developer must then write code that adapts to these new criteria. It is then amended and tested until the test passes.
There is one important difference, however. In test-driven development, the TDD process slightly extends the entire process in that even once the tests are passed with a viable code, the developer then proceeds to refactor the code for the whole process to be as streamlined and efficient as possible.
Business owners, developers, and TDD leads work together in a process known as acceptance TDD.
Test-driven development (TDD) is therefore an example of evolutionary development resulting in optimum code based on feedback, with as few flaws as possible. Likewise, as the TDD test is able to complete all functions for that unit early in the process, there is a reduced need with test-driven development to have developers engage in work further down the project life cycle. Test-driven development, therefore, affords significant amounts of time saved.
Why we should test
As mentioned earlier, developers feel as though testing creates extra work once they have already created the product code and seen it run efficiently in a given scenario. Why have the extra work created by a failing test? Test-driven development is also intimidating for those used to the code first approach.
However, it is clear that by not carrying out a test-driven development approach, last-minute testing and extra work are inevitable. Business leaders will request some minimal testing with just enough code to ensure that they are not going to market with a faulty app.
It is the code first approach, then, that entails the necessity of extra work at the final stages of creating a product.
With test first or test-driven development, the work is already complete, so time and effort are saved. Experienced developers that can also be TDD leads are therefore in demand.
We can see that the two approaches which incorporate testing in the initial core steps remedy the issues mentioned by developers cited above. Specifically:
As testing is included at the beginning of a project, it can be factored into the project plan’s life cycle. This will demonstrate how time is saved at the end of a project without extraneous testing and the subsequent debugging that this entails. It also saves on staff hours as more issues are dealt with at the beginning and there is less need for collaborative work to solve them throughout the project.
Provide seamless code
The test first and test-driven development approaches both produce product code only when the potential bugs and performance issues have already been met. Progression through the test suites with test passes produces code which by definition works and will work consistently across different browsers and machines.
The two test first approaches show how they function. That is, it will be immediately clear to a developer what a colleague was attempting to do first in writing the testable code and then in how it was refactored into a product code. Unlike the code first approach, where different developers might have different idiosyncratic methods and ways of putting code and tests together with little rhyme or reason, the staging and rationale behind TDD are clear and logical, from the first test fail to the final refactor stage.
Business Advantages of Testing
Time and budget: There are definite time and financial costs involved in testing, and this cannot be avoided. This is true of all of the approaches outlined above. However, by adopting a test-driven development (TDD) approach, these costs can be factored into the planning stage, avoiding later additional expenses. It speeds up time to market, and also saves costs from developer hours being extended.
Superior product: All apps are constantly updated by their developer teams. However, adopting the test-driven development (TDD) approach where the test covers not only the likely initial bugs but also works to produce better code at every step of the testing process. This will greatly improve brand quality recognition and customer trust.
Planning: Thorough planning helps form reliable deadlines, budgets, and time to market. Whether the software development requires end to end testing, integration testing, or unit testing, each test has its own metrics for time and cost. Test-driven development (TDD) is the most economical in that the testing process itself creates the production code and, therefore, the product. Here, the testing framework is the sandbox of creation.
Project management: A test, for example, a unit test or an acceptance test, requires the planning of actual code according to the business criteria for quality software. This produces concrete examples of success that are quantifiable and recordable. This makes employing freelancers for a software engineering project much more manageable as story points, KPIs, and deliverables for invoicing and performance management have more concrete data.
The test-driven development process is something that future proofs a project but also pays for itself because the costs are factored in prevent later financial burdens. It is the code first approach, not the TDD approach, which leads to awkward budgetary and developer issues where additional tests become necessary.
Avoiding testing is risky and almost guaranteed to cause serious issues with a product upon release. Including a TDD test, therefore, increases the probability of a successful launch and a satisfied customer.
Ultimately, test-driven development should be seen as a process that creates high-quality code and a product that performs well. Acceptance TDD is the way forward.