Chapitre 3
Testing and debugging
Lecture : 21 minQuiz de 16 questions
# Testing and debugging
## Notions on testing and debugging
### Introduction
Software is all around us, from the apps on our phones to the systems controlling airplanes. For software to be reliable and work correctly, it needs to be thoroughly tested and any errors (bugs) need to be removed. This lesson will introduce you to the fundamental concepts of software testing and debugging, explaining why they are crucial in software development.
### Key Concepts
#### What is Software Testing?
Software testing is the process of evaluating a software application to find if it meets the specified requirements and to identify any defects or errors. It's about checking if the software does what it's supposed to do and doesn't do what it's not supposed to do.
##### Purpose of Testing
* **Quality Assurance:** To ensure the software is of high quality, reliable, and user-friendly.
* **Bug Detection:** To find and fix errors (bugs) before the software is released to users.
* **Requirement Verification:** To check if the software meets all the customer's requirements.
* **Risk Reduction:** To minimize the risk of software failure in real-world use.
* **Performance Evaluation:** To assess how well the software performs under various conditions.
##### Importance of Testing
Without proper testing, software can have many issues, leading to:
* Unreliable applications.
* Data loss.
* Security vulnerabilities.
* Financial losses.
* Damage to reputation.
* User frustration.
#### Types of Testing
There are many types of testing, each serving a different purpose.
##### Unit Testing
* Tests individual components or modules of a software application in isolation.
* Performed by developers during the coding phase.
* Example: Testing a single function that calculates the sum of two numbers.
##### Integration Testing
* Tests how different modules or components interact with each other.
* Aims to uncover defects in the interfaces and interactions between integrated units.
* Example: Testing if the login module correctly passes user data to the profile module.
##### System Testing
* Tests the complete and integrated software system.
* Evaluates the system's compliance with specified requirements.
* Covers functional and non-functional requirements (e.g., performance, security).
* Example: Testing an entire e-commerce website, including user registration, product browsing, cart management, and checkout.
##### Acceptance Testing
* Tests conducted to determine if the software satisfies the end-user requirements and business needs.
* Typically performed by end-users or clients.
* Example: A client tests if the developed accounting software meets their daily operational needs.
##### Black-box Testing
* Tests the functionality of an application without looking at its internal structure or code.
* Testers interact with the software as an end-user would, based on requirements.
* Example: Testing a web form by entering data and checking if the output is correct, without knowing how the form processes the data internally.
##### White-box Testing
* Tests the internal structure, design, and implementation of the software.
* Requires knowledge of the internal code and how it works.
* Performed by developers.
* Example: A developer checks if all branches in an `if-else` statement are executed correctly.
#### What is Debugging?
Debugging is the process of finding and removing errors (bugs) from computer programs. Once a test reveals a bug, debugging helps to pinpoint the exact location and cause of the error, and then correct it.
##### Purpose of Debugging
* **Error Resolution:** To fix bugs and make the software work as intended.
* **Code Improvement:** Often involves understanding the code better, which can lead to improvements.
* **Stability:** To ensure the software is stable and performs reliably.
##### Debugging Process
The general debugging process involves these steps:
1. **Reproduce the Bug:** Confirm the bug exists and find a consistent way to make it happen.
2. **Isolate the Bug:** Pinpoint the specific section of code where the error occurs.
3. **Analyze the Cause:** Understand why the bug is happening. What condition or input leads to the error?
4. **Fix the Bug:** Modify the code to correct the error.
5. **Verify the Fix:** Rerun tests to ensure the bug is resolved and no new bugs have been introduced (regression testing).
#### Debugging Tools and Techniques
Developers use various tools and techniques to effectively debug their code.
##### Debuggers
* Specialized software tools that allow developers to execute their code step-by-step.
* They provide features like:
* **Breakpoints:** Pausing program execution at a specific line of code.
* **Step-by-step execution:** Running code one line at a time.
* **Variable inspection:** Viewing the current values of variables.
* **Call stack analysis:** Seeing the sequence of function calls that led to the current point.
##### Print Statements (or Console Logs)
* A simple but effective technique.
* Developers insert `print()` statements (or similar functions in other languages, e.g., `console.log()` in JavaScript) to display the values of variables or messages at different points in the code.
* Helps to trace the flow of execution and variable states.
##### Logging
* A more structured and persistent way to record information about program execution.
* Logging frameworks allow categorizing messages (e.g., INFO, WARNING, ERROR) and writing them to files or databases.
* Useful for long-running applications or when issues are hard to reproduce.
### Vocabulary
* **Bug:** An error, flaw, failure, or fault in a computer program or system that causes it to produce an incorrect or unexpected result, or to behave in unintended ways.
* **Defect:** Another term for a bug, often used in a more formal testing context.
* **Error:** A mistake, often made by a programmer, that results in a defect.
* **Testing:** The process of evaluating a software system or component with the intent to find errors.
* **Debugging:** The process of finding and resolving defects or errors within a computer program that prevent correct operation of computer software or a system.
* **Test Case:** A set of conditions or variables under which a tester will determine whether an application, software system, or one of its features is working as it was originally established for it to do.
* **Breakpoint:** An intentional stopping or pausing place in a program, put in place for debugging purposes.
* **Regression Testing:** Retesting existing software to ensure that changes or additions haven't introduced new bugs or broken existing functionality.
* **Module/Component:** A distinct and self-contained part of a larger software system.
### Examples
#### Example 1: Unit Testing a Calculator Function
Let's say you have a Python function to add two numbers:
```python
def add_numbers(a, b):
return a + b
```
A unit test for this function might look like:
```python
# Test Case 1: Positive numbers
result1 = add_numbers(2, 3)
print(f"Test Case 1: 2 + 3 = {result1}") # Expected: 5
# Test Case 2: Negative numbers
result2 = add_numbers(-1, -5)
print(f"Test Case 2: -1 + -5 = {result2}") # Expected: -6
# Test Case 3: Zero
result3 = add_numbers(0, 7)
print(f"Test Case 3: 0 + 7 = {result3}") # Expected: 7
```
If any `result` does not match the expected value, there's a bug in the `add_numbers` function.
#### Example 2: Debugging with Print Statements
Imagine you have a program that calculates the average of a list of numbers, but it's giving an incorrect result.
```python
def calculate_average(numbers):
total = 0
for num in numbers:
total += num
# Bug: Division by zero if numbers list is empty
average = total / len(numbers)
return average
my_list = [10, 20, 30]
print(f"Average: {calculate_average(my_list)}") # Expected: 20
empty_list = []
print(f"Average of empty list: {calculate_average(empty_list)}") # This will cause an error
```
To debug the `empty_list` case, you could add print statements:
```python
def calculate_average(numbers):
print(f"Debugging: Input numbers = {numbers}")
total = 0
for num in numbers:
total += num
print(f"Debugging: Total = {total}")
if len(numbers) == 0:
print("Debugging: List is empty, cannot calculate average.")
return 0 # Or raise an error
average = total / len(numbers)
print(f"Debugging: Length of numbers = {len(numbers)}")
print(f"Debugging: Calculated average = {average}")
return average
```
The print statements help identify that `len(numbers)` is 0 when `empty_list` is passed, leading to a `ZeroDivisionError`. The fix would involve checking if the list is empty before dividing.
### Exercises
1. Explain in your own words the main difference between software testing and debugging.
2. Name and briefly describe three types of software testing.
3. Why is it important to perform unit testing early in the development cycle?
4. Consider a program that asks a user for their age and prints "You are an adult" if the age is 18 or older, and "You are a minor" otherwise. Describe two different test cases you would use for this program.
5. If you encounter a bug in a program, what is the first step you should take in the debugging process?
6. List two advantages of using a dedicated debugger compared to using only print statements for debugging complex issues.
### Assignment
1. **Scenario Analysis:** You are developing a simple banking application. A user reports that when they try to transfer money, sometimes the transaction fails without any clear error message.
* What type of testing would have been most likely to catch this issue before release? Justify your answer.
* Outline the steps you would take to debug this reported issue.
2. **Code Correction:** The following Python function is intended to calculate the factorial of a number. However, it contains a bug.
```python
def calculate_factorial(n):
if n == 0:
return 1
else:
result = 0 # This line contains the bug
for i in range(1, n + 1):
result *= i
return result
print(f"Factorial of 5: {calculate_factorial(5)}") # Expected: 120, Actual: 0
```
* Identify the bug in the `calculate_factorial` function.
* Correct the bug.
* Write a simple test case to verify your corrected function works for `n=4`.
3. **Research & Report:** Research and write a short paragraph (50-100 words) about one common software bug that has caused significant problems in real-world applications (e.g., the Y2K bug, the Mars Climate Orbiter incident). Explain what the bug was and what its impact was.
### Summary
This lesson introduced you to the essential concepts of testing and debugging in computer science. We learned that **software testing** is about systematically evaluating software to find defects and ensure it meets requirements, covering various types like unit, integration, system, and acceptance testing, as well as black-box and white-box approaches. **Debugging**, on the other hand, is the process of identifying, analyzing, and fixing those defects. We explored the structured debugging process and useful tools such as debuggers and print statements. Both testing and debugging are indispensable practices in software development, contributing significantly to the quality, reliability, and security of software applications we use every day.
## Dry running
### Introduction
Welcome to this lesson on dry running! In computer science, writing programs is only half the battle. The other crucial half is making sure your programs work correctly and efficiently. Dry running is a fundamental technique that programmers use to test their code mentally, or on paper, before actually running it on a computer. It's like proofreading an essay before submitting it. This lesson will teach you how to effectively dry run your algorithms and code snippets to catch errors early and understand program flow better.
### Key Concepts
#### What is Dry Running?
Dry running, also known as a desk check, is the process of manually executing an algorithm or program code step-by-step to trace its execution and determine its output or behavior without the use of a computer. It's a mental or paper-based simulation of how the computer would process the instructions.
##### Purpose of Dry Running
* **Error Detection:** Identify logical errors, common mistakes, or unexpected behavior in the algorithm before writing or compiling the actual code.
* **Understanding Logic:** Gain a deeper understanding of how an algorithm works and how data flows through it.
* **Verification:** Confirm that an algorithm will produce the expected output for various inputs.
* **Debugging Aid:** When actual code fails, dry running can help pinpoint the exact location and cause of an error.
#### How to Dry Run
To effectively dry run an algorithm or pseudocode, you will typically use a **trace table**. A trace table is a simple table used to record the values of variables and the output of a program at each step of its execution.
##### Steps to Perform a Dry Run:
1. **Understand the Algorithm/Code:** Read through the entire algorithm or pseudocode to get a general idea of what it's supposed to do.
2. **Create a Trace Table:** Draw a table with columns for:
* **Line Number/Step:** To keep track of the current instruction being executed.
* **Variables:** A separate column for each variable used in the program (e.g., `num1`, `count`, `result`).
* **Output:** A column to record any values that would be displayed or printed by the program.
* **(Optional) Condition/Notes:** A column to record the evaluation of conditions in `IF` statements or loop conditions.
3. **Initialize Variables:** Fill in the initial values for any variables at the start of the program.
4. **Execute Step-by-Step:** Go through the algorithm line by line. For each instruction:
* Update the values in the variable columns as they change.
* Record any output in the output column.
* Carefully evaluate conditions for `IF` statements and loops to determine which path is taken.
5. **Continue Until End:** Keep tracing until the program finishes or a loop condition becomes false.
6. **Review the Trace:** Examine the final values in your trace table and the recorded output to see if they match your expectations. This helps identify where errors might be occurring.
#### Benefits of Dry Running
* **Cost-Effective:** It costs nothing but time and paper. Finding errors early saves significant time and resources compared to debugging live code.
* **Improved Problem-Solving:** Regular dry running hones your logical thinking and problem-solving skills.
* **Better Code Quality:** By catching errors early, you write more robust and reliable programs.
* **Enhanced Understanding:** It deepens your understanding of how program instructions are executed by a computer.
### Vocabulary
* **Dry Running (Desk Check):** Manually executing an algorithm or code step-by-step to trace its execution and verify its logic.
* **Trace Table:** A table used to record the values of variables and program output at each step during a dry run.
* **Algorithm:** A set of well-defined, step-by-step instructions to solve a problem or perform a task.
* **Pseudocode:** An informal high-level description of the operating principle of a computer program or other algorithm. It uses a mix of natural language and programming constructs.
* **Variable:** A named storage location in a computer program that can hold a value, which can change during program execution.
* **Debugging:** The process of identifying, analyzing, and removing errors (bugs) from computer programs.
### Examples
#### Example 1: Summing Numbers
Consider the following pseudocode that calculates the sum of numbers from 1 up to a given limit.
```pseudocode
1. START
2. INPUT limit
3. SET sum = 0
4. SET count = 1
5. WHILE count <= limit DO
6. SET sum = sum + count
7. SET count = count + 1
8. END WHILE
9. OUTPUT sum
10. END
```
Let's dry run this pseudocode with `limit = 3`.
| Line | limit | sum | count | Output |
|------|-------|-----|-------|--------|
| 2 | 3 | - | - | |
| 3 | 3 | 0 | - | |
| 4 | 3 | 0 | 1 | |
| 5 | 3 | 0 | 1 | |\(1 \le 3\) is TRUE |
| 6 | 3 | 1 | 1 | |
| 7 | 3 | 1 | 2 | |
| 5 | 3 | 1 | 2 | |\(2 \le 3\) is TRUE |
| 6 | 3 | 3 | 2 | |
| 7 | 3 | 3 | 3 | |
| 5 | 3 | 3 | 3 | |\(3 \le 3\) is TRUE |
| 6 | 3 | 6 | 3 | |
| 7 | 3 | 6 | 4 | |
| 5 | 3 | 6 | 4 | |\(4 \le 3\) is FALSE |
| 9 | 3 | 6 | 4 | 6 |
**Output:** 6
#### Example 2: Finding the Largest Number
Consider this pseudocode to find the largest of three numbers.
```pseudocode
1. START
2. INPUT num1, num2, num3
3. SET largest = num1
4. IF num2 > largest THEN
5. SET largest = num2
6. END IF
7. IF num3 > largest THEN
8. SET largest = num3
9. END IF
10. OUTPUT largest
11. END
```
Let's dry run this with `num1 = 10`, `num2 = 25`, `num3 = 15`.
| Line | num1 | num2 | num3 | largest | Output |
|------|------|------|------|---------|--------|
| 2 | 10 | 25 | 15 | - | |
| 3 | 10 | 25 | 15 | 10 | |
| 4 | 10 | 25 | 15 | 10 | |\(25 > 10\) is TRUE |
| 5 | 10 | 25 | 15 | 25 | |
| 7 | 10 | 25 | 15 | 25 | |\(15 > 25\) is FALSE |
| 10 | 10 | 25 | 15 | 25 | 25 |
**Output:** 25
### Exercises
For each of the following pseudocode snippets, create a trace table and determine the final output.
#### Exercise 1
```pseudocode
1. START
2. SET x = 5
3. SET y = 10
4. SET z = x + y
5. IF z > 12 THEN
6. SET x = z - y
7. ELSE
8. SET x = y - z
9. END IF
10. OUTPUT x
11. END
```
#### Exercise 2
```pseudocode
1. START
2. SET product = 1
3. SET counter = 1
4. WHILE counter <= 4 DO
5. SET product = product * counter
6. SET counter = counter + 1
7. END WHILE
8. OUTPUT product
9. END
```
#### Exercise 3
```pseudocode
1. START
2. INPUT grade
3. IF grade >= 80 THEN
4. OUTPUT "Excellent"
5. ELSE IF grade >= 60 THEN
6. OUTPUT "Pass"
7. ELSE
8. OUTPUT "Fail"
9. END IF
10. END
```
Dry run this for `grade = 75` and `grade = 90`.
### Assignment
1. **Scenario Analysis:** You are given the following pseudocode. Dry run it with the inputs `a = 15`, `b = 7`, and `c = 20`. Create a full trace table and state the final output.
```pseudocode
1. START
2. INPUT a, b, c
3. SET max_val = a
4. IF b > max_val THEN
5. SET max_val = b
6. END IF
7. IF c > max_val THEN
8. SET max_val = c
9. END IF
10. OUTPUT max_val
11. END
```
2. **Error Detection:** The following pseudocode is intended to count down from 5 to 1. Identify any logical errors by dry running it, and then correct the pseudocode.
```pseudocode
1. START
2. SET count = 5
3. WHILE count < 1 DO
4. OUTPUT count
5. SET count = count - 1
6. END WHILE
7. END
```
3. **Problem Solving:** Write pseudocode for an algorithm that takes two numbers as input and outputs their sum. Then, dry run your pseudocode with the inputs `5` and `8` to show the output.
### Summary
Dry running is an essential skill for any programmer. It involves manually stepping through an algorithm or program to simulate its execution, track variable values, and predict the output. By using a trace table, you can systematically uncover logical errors, understand complex program flows, and ensure your algorithms are correct before you even write a single line of actual code. Mastering dry running will save you time, improve your debugging abilities, and lead to the creation of more reliable and efficient programs.
## Integration activities
# Integration Activities\n\n## Introduction\nWelcome to our lesson on Integration Activities in Computer Science! After individual components (modules) of a software system have been developed and thoroughly tested on their own (unit testing), the next crucial step is to combine them and ensure they work together seamlessly. This process is known as integration testing, and it's a vital part of finding errors that arise when different parts of a system interact. Understanding how to integrate and debug these integrated components is key to building robust and reliable software.\n\n## Key Concepts\n\n### What is Integration Testing?\nIntegration testing is a type of software testing where individual software modules are combined and tested as a group. The primary goal is to identify defects in the interfaces and interactions between these integrated modules.\n* **Purpose:** To expose faults in the interaction between integrated units (modules).\n* **Contrast with Unit Testing:** Unit testing focuses on individual components in isolation. Integration testing focuses on how these components work together.\n* **Contrast with System Testing:** System testing evaluates the complete, integrated software product to ensure it meets specified requirements. Integration testing is a step before system testing.\n\n### Types of Integration Testing Strategies\n\n#### 1. Big Bang Approach\n* **Definition:** All modules are integrated at once and then tested as a complete system.\n* **Pros:** Simple to implement for very small projects; requires less effort in planning test cases.\n* **Cons:** Extremely difficult to pinpoint the exact location of defects when a failure occurs because many modules are involved. Requires all modules to be completed before testing can begin, leading to potential delays.\n\n#### 2. Incremental Approach\nThis approach involves integrating modules one by one or in small groups, allowing for earlier defect detection and easier fault isolation.\n\n##### a. Top-Down Integration\n* **Definition:** Testing starts from the main control module and moves downwards, integrating lower-level modules sequentially. Stubs are used to simulate lower-level modules that are not yet developed or integrated.\n* **Pros:** Architectural flaws can be detected early. Modules critical to the system's overall structure are tested first.\n* **Cons:** Stubs can be complex to write. Lower-level modules might not be thoroughly tested until late in the process.\n\n##### b. Bottom-Up Integration\n* **Definition:** Testing starts from the lowest-level modules and moves upwards, integrating them into higher-level modules. Drivers are used to simulate higher-level modules that call the modules being tested.\n* **Pros:** Low-level modules, which are often reused, are thoroughly tested first. Easier to write drivers than complex stubs.\n* **Cons:** Architectural flaws might be detected late. The main control module is tested last.\n\n##### c. Sandwich/Hybrid Integration\n* **Definition:** This approach combines both Top-Down and Bottom-Up strategies. It typically involves a top-down approach for higher-level modules and a bottom-up approach for lower-level modules, meeting in the middle.\n* **Pros:** Balances the benefits of both top-down and bottom-up. Efficient for large and complex systems.\n* **Cons:** Can be more complex to manage due to the need for both stubs and drivers, and coordinating multiple integration paths.\n\n### Stubs and Drivers\n* **Stub:** A dummy program or module that simulates the behavior of a component that is *called by* the module currently being tested. It provides a simplified response to the calling module when the actual called module is not yet available or fully functional.\n* **Driver:** A dummy program or module that simulates the behavior of a component that *calls* the module currently being tested. It acts as a temporary replacement for a higher-level module to test a lower-level module.\n\n### Debugging during Integration\nWhen integration tests fail, debugging involves identifying the source of the problem. This often includes:\n* **Interface Issues:** Mismatched data types, incorrect parameter passing, or unexpected return values between modules.\n* **Data Flow Problems:** Data not being correctly transferred or transformed as it moves between integrated components.\n* **Control Flow Errors:** The sequence in which modules are called or execute is incorrect.\n* **Tools and Techniques:** Using logging, setting breakpoints, step-through debugging, and analyzing error messages.\n\n## Vocabulary\n* **Integration Testing:** Combining and testing individual software modules as a group.\n* **Module:** A distinct and self-contained part of a software system, often performing a specific function.\n* **Stub:** A placeholder for a called module that hasn't been developed yet.\n* **Driver:** A placeholder for a calling module that hasn't been developed yet.\n* **Big Bang Integration:** Testing all modules together at once.\n* **Incremental Integration:** Integrating and testing modules in stages.\n* **Top-Down Integration:** Integrating from main control module downwards, using stubs.\n* **Bottom-Up Integration:** Integrating from lowest-level modules upwards, using drivers.\n* **Sandwich Integration:** A hybrid approach combining top-down and bottom-up.\n* **Interface:** The point of interaction or communication between two modules.\n* **Debugging:** The process of identifying, analyzing, and removing errors (bugs) from software.\n\n## Examples\nLet's consider an online library system with three main modules:\n1. **`UserAuth`:** Handles user login and registration.\n2. **`BookSearch`:** Allows users to search for books.\n3. **`BorrowReturn`:** Manages borrowing and returning books.\n\n### Big Bang Example\nAll three modules (`UserAuth`, `BookSearch`, `BorrowReturn`) are developed and then combined into one large system. Testing begins by trying to log in, search for a book, and borrow it. If an error occurs (e.g., a book cannot be borrowed after searching), it's very difficult to immediately tell if the problem is in `UserAuth`'s interaction with `BorrowReturn`, or `BookSearch`'s output to `BorrowReturn`, or an internal issue within one of the modules that only surfaces during interaction.\n\n### Incremental (Bottom-Up) Example\n1. **Test `BookSearch`:** Independently test `BookSearch` to ensure it retrieves correct results. Use a **Driver** to simulate the main application calling `BookSearch` functions.\n2. **Test `BorrowReturn`:** Independently test `BorrowReturn` to ensure it can mark books as borrowed/returned. Use a **Driver** to simulate a user or `BookSearch` module initiating these actions.\n3. **Integrate `BookSearch` and `BorrowReturn`:** Combine these two modules. Test scenarios like
Quiz du chapitre
16 questions — vérifie chaque réponse pour voir l'explication.