PC

Debugging and Testing Notes

Debugging

Debugging is the process of finding and fixing errors (bugs) in code. It involves three main steps:

  1. Recognizing that an error exists.

  2. Locating the source of the error.

  3. Resolving the error.

### Types of Debugging
Rubber Duck Debugging: This technique involves explaining the code and the problem to an inanimate object (like a rubber duck). The act of explaining the code step-by-step can often reveal the error in logic.

Interactive Debugger (PDB): This involves running the code in debug mode with breakpoints. Breakpoints pause the execution of the code at specific points, allowing developers to inspect the state of the program (e.g., variable values) at that point. The interactive debugger allows stepping through the code line by line.

### Exercises in Debugging
Password Checker: The exercise involves opening a file named password_debug.py and identifying and fixing the error within the code.

Payroll System:


  • Exercise 2: A new version of a payroll system has been deployed but isn't calculating payroll for any employee. The task is to debug payroll_main.py to find and fix the issue.


  • Exercise 3: After fixing the initial bug, discrepancies arise in the payroll calculations for William Clark and Amelia Thompson:

  • William Clark expected €1678.10 but received €412.0.

  • Amelia Thompson expected €1798.90 but received €1798.0.

  • Despite the code appearing correct upon review and tests passing, a debugging session of payroll_main.py is required to identify and correct any errors within the program.

Testing

Testing is a critical part of software development that helps to ensure the quality and reliability of code.

### Types of Testing
Unit Testing: Testing the smallest possible pieces of a program (individual units or components). It forms the foundation for other types of testing.
Integration Testing: Testing the interactions between related units to ensure they work together correctly.
System Testing: An extreme form of integration testing that tests the entire system as a whole.
Regression Testing: Ensuring that new code changes do not negatively impact existing functionalities. This involves re-testing the entire application or significant parts of it after modifications.
User Acceptance Testing (UAT): Involving end-users in testing the software to ensure it meets their requirements and is ready for production release.

Stress Testing: Pushing the system beyond its specified limits to observe its behavior under extreme conditions and ensure it doesn't crash.

Test-Driven Development (TDD)

Test-Driven Development (TDD) is a software development practice where developers write automated tests before writing the actual code. The TDD cycle involves:

  1. Write tests.

  2. Make sure the tests fail.

  3. Write the code.

  4. Make the tests pass.

  5. Repeat (sometimes refactoring before repeating).

Doctests

  • Doctest will be the mainstay of your testing toolkit

  • Doctest tests are written in plain text.

  • Doctest extracts the tests and ignores the rest of the text

  • Tests can be embedded in human-readable explanations or discussions.

Creating a Doctest

  1. Open a new text file in your editor and name it test.txt.

  2. Insert the test cases (IDLE input and output) into the file as shown below:

This is a simple doctest that checks some of Python's arithmetic operations.
    >>> 2 + 2
    4
    >>> 3 * 3
    9
  1. Run the doctest from the command line using:

python -m doctest test.txt

Or, create a small Python code file, such as:

import doctest
    doctest.testfile("test.txt")

Doctest Directives

  • +SKIP: Skips a test.

>>> 'This test would fail.'  # doctest: +SKIP
  • +ELLIPSIS: Allows matching any substring in the actual output, useful for ignoring variable parts of the output.

func(56, "hello")  # doctest: +ELLIPSIS
    <mocker.Mock object at ...>
  • More directives can be found at the provided link: https://docs.python.org/2/library/doctest.html#option-flags-and-directives

Embedding Doctests in Python Docstrings

To embed doctests within a Python docstring, follow this structure:

def testable(x):
  """
The `testable` function returns the square root
of its parameter, or 3, whichever is larger.
  >>> testable(7)
  3.0
  >>> testable(16)
  4.0
  >>> testable(9)
  3.0
  >>> testable(10) == 10 ** 0.5
  True
  """
  if x < 9:
    return 3.0
  return x ** 0.5

```

Run the tests using the command line:

python -m doctest -v test.py

Exercise

Write a Python program to find all the unique combinations of 3 numbers from a given list of numbers, adding up to a target number.

  • Include in the docstring the doctests for the following test cases:

Original list of numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9]
    Target value: 12
    Combine three numbers whose sum equal to a target number: [(1, 3, 8), (1, 4, 7), (1, 2, 9), (1, 5, 6), (3, 4, 5), (2, 3, 7), (2, 4, 6)]
    Original list of numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9]
    Target value: 17
    Combine three numbers whose sum equal to a target number: [(4, 5, 8), (2, 6, 9), (3, 5, 9), (2, 7, 8), (4, 6, 7), (3, 6, 8), (1, 7, 9)]
def findcombinationsofthree(nums, targetval):

    """

    Find all