knowledge-kitchen

Software Testing - Ensuring Software Works as Expected

Validating the functionality of a codebase.

  1. Overview
  2. Automation
  3. Static Analysis
  4. Code Linting
  5. Unit Testing
  6. Code Coverage
  7. Integration Testing
  8. User Acceptance Testing
  9. Regression Testing
  10. System Testing
  11. Test-Driven Development
  12. Behavior-Driven Development
  13. Conclusions

Overview

Substance

Testing helps verify that the software performs as expected.

Style

Testing can also help verify that the software has been written well.

Sanity

Testing can also help prove that the software is usable and that you haven’t built it all for nil.

Automation

Rise of the Robots

While much of running software tests can now be automated, a few tasks still require humans.

Static Analysis

Concept

Static analysis tools perform a static analysis of the codebase, meaning the code need not be executed for it to be analyzed and for problems to be reported.

Examples of static analysis include:

Advantage

Static analysis linting and type checking tools are especially useful when a programming language is interpreted, since interpreters do not report compilation errors, and errors are often only discovered at runtime.

Code Linting

Concept

A code linter is a tool that automatically checks both syntax and style of code.

Features

A code linter is a software tool that can…

Advantages

Code linters offer some advantages over human code reviews, such as:

Recommendations (Javascript)

Use ESLint linter with the Prettier formatter for Javascript.

Recommendations (Javascript) continued

Once you have installed the Prettier or other similar formatter extension to Visual Studio Code, you can have it auto-format your code every time you save a file. To turn this on, go to Visual Studio Code’s settings and search for “format on save”. Activate the checkbox.

Setting to format on save in VSCode

Recommendations (Python)

Use pylint for Python.

Type Checking

Concept

Type checking is a type of static analysis that verifies the data types of variables, function arguments, and object properties. Setting these values to a type that contradicts the type annotations added to the code results in an error.

Advantages

Type checking offers a few specific advantages that make it attractive, especially for large teams and projects, where the quality of people and processes may vary:

Disadvantages

Type checking also has some notable disadvantages, especially for small teams and projects attempting to move quickly:

Recommendations (Javascript)

For small projects and teams, it is recommended not to use a type checker. However, if you insist on using a type checker, TypeScript is the most popular type checker for Javascript at the time of this writing.

An example of function with Typescript annotations for the parameter variable and return value:

function printToConsole(s: string): void {
  console.log(s)
}

printToConsole(`Hello world`)

Custom object and array structures can be defined as well.

Recommendations (Python)

Should one desire type checking, Python allows (but does not enforce) type hints as part of the language. The mypy type checking tool can be used to enforce typing.

# an example function with a type hint for the parameter variable and return value
def print_to_console(s: str) -> None:
    print(s)

Custom object and array structures can be defined as well.

Unit Testing

Concept

A unit is the smallest testable unit of code - typically a function.

Javascript Example

A unit test example in Javascript using the mocha unit testing framework and Node.js’s built-in assertion library, assert:

// use node.js's built-in assert assertion library
const assert = require("assert")

// a set of tests of array functions
describe("Array", function () {
  // one particular unit test
  describe("#indexOf()", function () {
    // assert what should be returned
    it("should return -1 when the value is not present", function () {
      // test that assertion
      assert.equal(-1, [1, 2, 3].indexOf(4))
    })
  })
})

Python Example

A unit test example in Python using pytest:

import pytest
from some_package import some_module

class Tests:

  def test_some_function(self):
    '''
    Verify some_function() returns a non-empty string.
    '''
    actual = some_module.some_function() # get the actual return value of the function
    assert isinstance(actual, str), f"Expected some_function() to return a string. Instead, it returned {actual}"
    assert len(actual) > 0, f"Expected some_function() not to be empty. Instead, it returned a string with {len(actual)} characters"

Features

Unit tests are performed on each unit in isolation, in the sense that they…

Advantages

Unit testing has discrete advantages that become increasingly important as a project grows in complexity and age.

Recommendation

Use mocha and chai for Javascript unit testing.

Integration Testing

Concept

Whereas unit testing tests units in-situ in isolation, integration testing tests units in vivo.

Features

Integration tests…

Code Coverage

Concept

The term code coverage refers to the percent of all code which is executed when unit and integration tests are run.

Limitations

Code coverage does not indicate that the code has been tested in all possible scenarios

Recommendation (Javascript)

Use c8 or istanbul for Javascript code coverage analysis.

{
    "scripts": {
      "test": "nyc mocha --timeout=3000"
    }
}
npm test

Recommendation (Python)

Use [coverage.py](https://coverage.readthedocs.io/ for Python code coverage analysis.

User Acceptance Testing

Concept

User Acceptance Testing (UAT) …

Scripts

User Acceptance Tests test users in specific use cases or user stories.

Regression Testing

Concept

The term regression testing refers to the re-running of old tests when new tests are run.

System Testing

Concept

Testing of the non-functional requirements, such as …

Test-Driven Development

Concept

Test-Driven Development (TDD) is the practice of writing tests, particularly unit tests, before production code is written.

Advantages

Test-Driven Development has several touted benefits:

Criticisms

Test-Driven Development has been attacked on many fronts:

Behavior-Driven Development

Concept

An alternative preferred by some to Test-Driven Development is Behavior-Driven Development (BDD).

Conclusions

You now have experienced a nice-and-easy overview of the different categories of software testing in common practice. The next step would be to try them out!