Why Functional Testing: A Real-Life Perspective
Tags: webdev, javascript, testing, react
Published: 2023-01-19 19:05:28

Functional testing is an important step in building quality applications. It is a process of testing a software application to ensure that it meets its specified requirements and works correctly. In simple terms, functional testing checks if the application is working as it should.

## Introduction

Functional testing is a testing process that validates the software system against functional requirements. The purpose of Functional testing is to test each functionality of the software application, by providing apt input, output verification against the Functional requirements. In other words, functional testing is a type of testing whereby the system is tested against the function requirement/specification.

> A real-life example of the importance of functional testing is a website for a retail store. If the website does not work correctly, customers may have trouble making purchases or finding the products they need. This can lead to lost sales and a negative impact on the store's reputation. However, if functional testing is done, any issues with the website can be identified and fixed before it is released to the public. This ensures that customers have a positive experience and are more likely to return to the store in the future.

There are many reasons why functional testing is a must-have for building high-quality applications. One of the main reasons is that it helps to find and fix bugs early on in the development process. When bugs are found and fixed early, it saves time and money in the long run. It also helps to ensure that the final product meets the needs of the user.

## Why automate Functional Tests?

You might be wondering why we need to write these tests, can't we just run the app and test like a regular user would? Well, Automation can certainly reduce time and effort in executing functional tests. Human error can also be lowered, preventing bugs from slipping past the test phase. However, new implementations can break existing features and we can be sure to catch them early enough from our existing test cases.
Although automated testing can never replace manual tests, having an ideal mix of the two will prove to be vital to have the desired quality in Software projects.

## Behaviour Driven Development (BDD)-style assertions

Writing your tests in a declarative-style allows the reader to get the grab instantly. When you write imperative code that is packed with conditional logic, the reader is forced to exert more brain-CPU cycles. In that case, code the expectation in a human-like language, declarative BDD style using `expect` or `should` and not using custom code.

```jsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';

describe('MyComponent', () => {
    it('should display the correct title', () => {
        render(<MyComponent />);
        const text = screen.getByText('My Component!');
        expect(text).toBeInTheDocument();
    });

    it('should display the correct number of buttons', () => {
        render(<MyComponent />);
        const buttons = screen.getAllByRole('button');
        expect(buttons.length).toBe(3);
    });
});
```

## Process Workflow for Functional Testing

Generally, functional testing in detail follows the steps below:   

- Determine which functionality of the product needs to be tested. This can vary from testing main functions, messages, error conditions and/or product usability.
- Create input data for functionalities to be tested according to specified requirements.
- Determine acceptable output parameters according to specified requirements.
- Execute test cases.
- Compare actual output from the test with the predetermined output values. This reveals if the system is working as expected.


## Functional Testing Use Case Examples:

Take an online HRMS portal where the employee logs in with his user account and password. On the login page, there are two text fields for the username & password, and two buttons: `Login` and `Cancel`. Successful login takes the user to the HRMS home page and `Cancel` will close the login.

Specifications are as shown below:

1. The user id field takes a minimum of 6 characters, a maximum of 10 characters, numbers`(0-9)`, letters`(a-z, A-z)`, special characters `(only underscore, period, hyphen allowed)` and it cannot be left blank. User id must begin with a character or a number and not special characters.

2. Password field takes a minimum of 6 characters, a maximum of 8 characters, numbers `(0-9)`, letters `(a-z, A-Z)`, special characters (all), and cannot be blank.

The use-case scenario above can be tested through a variety of functional testing techniques which can be classified into two broad categories:

- Positive testing
- Negative testing

### 1. End-user based/System Tests

A _positive testing_ category that Test the system to gauge if all components are working perfectly in combination.

In the example, this would entail testing the customer journey – HRMS application loading, entering accurate credentials, directing to the home page, performing tasks, logging out of the system. This test ensures that this workflow proceeds and completes without any errors.

### 2. Equivalence Tests

A _negative testing_ category that ensures Test data is segregated into partitions called equivalence data cases. In this test, data in each partition must respond in the same way. Consequently, you only need to test one condition across all partitions. If the condition does not work in one partition, it won’t work in any of the others.

In the example, since the user id field can accommodate a maximum of `10 characters`, it should behave the same way anytime `data > 10` is entered.

### 3. Boundary Value Tests

These tests are used to check how the system behaves when data limits are implemented. _(Negative Testing)_

In the example, since the user id requires a minimum of `6 characters`, this test will be used to check how the system responds when less than `6 characters` are entered.

### 4. Decision-based Tests

These tests are initiated to check for possible system outcomes when a particular condition is met. _(Negative Testing)_

In the example, the following decision-based tests can be undertaken:

- If incorrect credentials are entered, the system should inform the user and reload the login page.
- If correct credentials are entered, the system should take the user to the home page UI.
- If correct credentials are entered but the user wants to cancel login, the system should not direct to the home page UI.
- Instead, it should reload the login page.


### 5. Alternate Flow Tests

Alternate path tests are run to validate all the possible ways that exist, other than the main flow to accomplish a function.  _(Positive Testing)_

### 6. Ad-hoc Tests

These tests uncover discrepancies that might not have been identified in any of the other tests. Ad-hoc tests are targeted towards breaking the system and checking its response. _(Negative Testing)_

For Example, a sample test case would be:

_A user is logged in, but the admin deletes the user account while he is performing some operations. It would be interesting to see how the application handles this gracefully._

> In conclusion, functional testing is a must-have for building high-quality front-end applications. It helps to find and fix bugs early on, ensures compatibility with different devices and browsers, and helps to ensure a positive user experience. By taking the time to perform functional testing, developers can ensure that their final product is of high quality and meets the needs of the user.

Keep building! 🚀