What's testing for, anyway? Good developers build functional software by writing functional code, right? What's so complicated about that?
Well, we are human. (Yes, even developers are human!) And humans make mistakes.
And mistakes in code can be costly…
What can go wrong when you don’t test
Let's look a few other famous testing fails:
Samsung Note 7
A real world example of catching a bug only after the application is in production is the Samsung Note 7 mobile phone. It's speculated that one of the problems the Note 7 phones faced involved their battery management system. This system monitors electric current and stops the charging process when the battery is fully charged. Having a error in this system could lead the battery to overcharge, become unstable, and eventually explode. 🔥This issue cost Samsung nearly $17 billion. Had this been noticed at an early stage, a lot of money, headaches, and PR stress could have been saved.
EDS Child Support System
In 2004, EDS introduced a highly complex IT system to the U.K.’s Child Support Agency (CSA). At the exact same time, the Department for Work and Pensions (DWP) decided to restructure the entire agency. The two pieces of software were completely incompatible, and irreversible errors were introduced as a result. The system somehow managed to overpay 1.9 million people and underpay another 700,000. It also caused $7 billion in uncollected child support payments, a backlog of 239,000 cases, 36,000 new cases “stuck” in the system, and has cost the UK taxpayers over $1 billion to date.
NASA’s Mars Climate Orbiter
On its mission to Mars in 1998, the Climate Orbiter spacecraft was ultimately lost in space. Although the failure bemused engineers for some time, it was revealed that a subcontractor on the engineering team failed to make a simple conversion from English units to metric.
An embarrassing lapse that sent the $125 million craft fatally close to Mars’ surface after attempting to stabilize its orbit too low. Flight controllers believe the spacecraft plowed into Mars’ atmosphere where the associated stresses crippled its communications, leaving it hurtling on through space in an orbit around the sun.
Consider a scenario
Time to put yourself in the shoes of a professional to start reflecting on common problems that systems face in the software development lifecycle:
As a newly hired developer, you join a project and need to support the next set of big features for the software. The system is a hotel-oriented software that allows visitors to register with the company, make a reservation for a room, and order services like room service, laundry, and a spa treatment. The system has been running for a few months, and the users consist primarily of hotel employees. They are comfortable using it, so they will expect the system to continue working normally as new features are introduced. Sometimes they complain about encountering unexpected issues like unresponsive buttons, time-outs, and duplicated entries.
In the future, as the company website gets re-designed, the system will become widely available to customers and accessible online by thousands of users. Eventually, the system will provide an API that can connect the current website and a mobile application that can be used by both employees and customers.
Because of the nature of the system, it contains a set of specific rules that need to be enforced, and some of them need to be considered as part of everyday operations. You will be in charge of making sure those changes take place and allow the system to continue functioning.
Even though there isn't a lot of documentation about the business rules, they are generally known by the personnel. Previous developers documented their coding decisions and placed descriptive comments in portions to ensure that vital parts of the system are handled carefully if they are changed in the future. The system is tested by employees attempting to use the latest version to see if it works as expected.
As a developer, some questions should come to mind as you start going through the current code and the new features coming to the system. Here are some to think about:
Why do users get errors when using the system in the first place?
How do they handle the problems to be repaired?
How are the business rules defined in the code so they follow the organization's standards?
What happens if other developers are in charge of fixing bugs, adding more functionalities, or ensuring that the system continues working as normal?
How do they check for side effects of new changes?
How confident can developers be with their code base, which might contain comments explaining decisions that took place several weeks ago? What if those comments are outdated or dead code?
When you start with a "green field" project (typically used to identify brand new projects without an existing code-base), you may not worry about these questions since most of the time, as developers, we focus on taking care of the project's key aspects: requirements, design, security, making progress, meeting delivery deadlines, and eventually testing the completed software.
The reality is, your software doesn't need to be "delivery-ready" to start testing it. To ensure that your software works as expected, you can make your project self-testable as you build it, even from day one. From making small changes in your code to having a fully functional API, your project will benefit from having testing capabilities. Even if your project doesn't have any testing practices yet beyond manual testing, it's never too late to apply good testing practices to your code. Don't wait for your customer or manager to question the quality of your code!
Understand the need for testing
Bringing new functionalities to a system is a natural part of development. Even after an application gets released, eventually you will be requested to add or remove specific functionalities depending on user needs.
Bug fixing is a key step in making software functional enough to allow users to get things done efficiently. Ideally, your users should never face bugs in the software they use; however, it's not reality. The key is how organizations handle, identify, and fix bugs as quickly as possible.
Bugs that are identified during the development phase of a project are the cheapest to mitigate. The ones that escape early detection become expensive and time-consuming, often requiring more people to get involved. Because of that, it's important to establish testing that covers the system and validates the correctness of the requirements within the system.
Besides testing an application inside an organization (a company, a group of developers, or a QA team), it's important to test at the codebase level to provide feedback on the correctness. This allows developers to be confident that their code is functional, has a minimum of errors, and the remaining ones are found quickly. This assurance can reduce the need for later testing, boost new functionality rollouts, and eventually lower costs associated with buggy software (including bug triage, fixing, tracking, and new deployments once they are mitigated).
Testing makes you a better developer
It's important that you produce high-quality code that solves problems in a programming language. In other words, fellow developers should easily understand your code, and it integrates seamlessly into an existing codebase. In fact, key characteristics of a good developer include:
an ability to programmatically solve a problem at hand
and an ability to produce quality code while solving that problem.
Producing quality code is all on you! 😎 There are two ways to approach this:
Be reactive - identify and eliminate bugs as you find them
Be proactive - write tests to prevent bugs from happening in the first place
Why do I have to test? Aren’t there quality control teams for that?
You've probably heard about the quality assurance (QA) or quality control (QC) teams. As their names suggest, they are responsible for ensuring the quality of software. Their job is, indeed, to test and identify all the bugs! And, believe me, you'll keep them busy. 😉
Still, as a professional developer, you must do everything possible to guarantee that your code works as intended. Never write a piece of code without testing it yourself. Do not rely on someone else to do so.
But isn’t testing really expensive and time-consuming?
It may seem that way initially, but testing proactively during the development stage is far less costly than having to fix a bug once something is already in production. It’s worth it to check and double-check your work during the early phases, so you don’t get stuck spending money on cleaning up a mess. It’s certainly worth the time invested.
What exactly are tests, anyway?
Tests allow you to check that a functionality that you've developed is operational. A functionality could be an algorithm, a piece of code, or even a whole program. There are lots of different types of tests, but you can break them up into two categories: manual tests and automatic tests.
Manual tests should be your first reflex as a developer, as soon as you write some code. You launch the application, and you click and poke around to make sure that it's working correctly. These kinds of tests are essential, but they're also a bit time-consuming, repetitive, and therefore expensive. Also, who wants to spend hours testing and retesting an application after each little correction or change? 😵 That's where automatic tests come in!
Automatic tests allow you to save time by automatically and quickly checking all the functionalities of your application. On top of being fast, they're a lot more reliable than error-prone humans. Plus, machines rarely complain when you give them a ton of repetitive work. 😉 That's why we'll be focusing on automatic tests in this course.
The scope of testing applications may depend on the needs and on the capacity of the team to organize, code, and maintain tests. You and your team members can establish good practices from a combination of manually testing the software as you develop it, having others look at and try your product before it gets released (beta testing), and provisioning it with the infrastructure to self-test regularly.
Types of automatic tests
Let's take a look at some of the most common automatic tests:
Unit tests - These test a section of code which is isolated from any dependencies. These are simple to develop, can be executed quickly, and allow you to check small sections of your code immediately.
Mock tests - These are unit tests that test a "mock" of a section of code rather than the actual section of code itself.
Integration tests - These check whether all these sections of isolated code work together correctly. They generally take longer than unit tests to execute and can test dependencies that the developer has control over, like databases or files.
For the purpose of this course, we will cover these three most used testing approaches: unit testing, mock testing, and integration testing.
You don't need to wait until the software is "ready" to start testing it.
The sooner you start testing, the better.
Manual testing is not the only way to test an application.
Business-critical rules can be used for establishing a basement for testing purposes.
It's highly recommended to test software for key activities in development, including:
Adding new features
Extending current features and adapting code
Enhancing code and refactoring
Bug fixing in general