Core Concepts in Software Testing and Code Quality
Graphs and Cyclomatic Complexity
A graph is a structure composed of nodes (also called vertices) and the connections between them, known as edges or arcs. They are used to represent relationships between elements.
Graph Types
- Directed: Connections have a specific direction (e.g., A → B).
- Undirected: Connections have no specific direction (e.g., A – B).
McCabe’s Cyclomatic Complexity
Cyclomatic complexity measures the number of linearly independent paths through a program’s source code. This metric helps identify the minimum number of tests required to cover all possible paths.
Formulas
- V(G) = Edges – Nodes + 2
- V(G) = Closed regions of the graph
- V(G) = Condition nodes + 1
White Box vs. Black Box Testing
Black Box Testing
This method tests the functionality of an application without knowing its internal structure or logic. Testers only interact with inputs and observe the outputs.
Key Techniques
- Equivalence Classes: Divides inputs into groups (valid and invalid) and tests one representative input from each group.
- Boundary Value Analysis: Tests values at the boundaries of input domains (e.g., minimum and maximum).
- Random Testing: Generates random inputs to check the application’s stability and robustness.
Practical Application
- Identify equivalence classes for both valid and invalid inputs.
- Choose representative values from each class and design test cases.
White Box Testing
This method requires knowledge of the internal logic and structure of the code. Testers analyze the code directly to verify internal paths and structures.
Code Coverage Metrics
- Statement Coverage: Ensures every line of code is executed at least once.
- Decision Coverage: Ensures each decision (e.g., an if-statement) evaluates to both true and false at least once.
- Path Coverage: Aims to execute all possible paths from the start to the end of the program.
Practical Application
- Draw a control-flow graph of the code.
- Calculate the cyclomatic complexity to determine the number of paths.
- Design tests to cover all identified paths.
Fundamentals of Version Control
Core Concepts
- Repository: A central storage location for project files and their revision history.
- Revision/Version: A specific snapshot of the stored data at a point in time.
- Tagging: Marking a specific version, typically at a significant point in a project’s development, like a release.
- Trunk: The main line of development in a project, often called ‘main’ or ‘master’.
- Branch: A parallel version of the code created to develop new features or fix bugs without affecting the trunk.
- Checkout: The action of creating a local working copy of the project from the repository.
- Commit: The action of saving changes from the local copy back to the repository.
- Export: Creating a clean copy of the project files without version control metadata.
- Import: Uploading local folders and files to a repository for the first time.
- Update: Synchronizing the local copy with the latest changes from the repository.
- Merge: The process of combining changes from different branches into a single branch.
- Conflict: An issue that occurs when changes from different sources clash, often when two users modify the same part of a file.
- Resolve Conflict: The process of manually merging conflicting changes to resolve a conflict.
Version Control System Types
- Local: Version management is handled in local folders on a single computer.
- Centralized (e.g., SVN): A client-server model where a single central server holds the entire repository.
- Distributed (e.g., Git): Every developer has a full, independent copy of the repository. Git is the most popular distributed system today.
Software Testing Documentation
- Test Plan: Outlines the general strategy, scope, resources, and schedule for testing activities.
- Test Design Specification: Expands on the test plan with detailed test conditions and approaches.
- Test Case Specification: Details the specific inputs, execution conditions, and expected results for a single test.
- Test Procedure Specification: Provides step-by-step instructions for executing a test case.
- Test Log: A chronological record of events that occurred during test execution.
- Test Incident Report: Documents any event during testing that requires investigation, such as a defect or an unexpected result.
- Test Summary Report: Summarizes all testing activities and results for stakeholders.
Code Refactoring Principles
Refactoring is the process of restructuring existing computer code without changing its external behavior. Its purpose is to improve the code’s clarity, performance, and maintainability.
When to Refactor
- Duplicated code
- Very long methods
- Large, unwieldy classes
- Methods with too many parameters
- A class that requires frequent changes
Common Refactoring Patterns
- Renaming variables and methods for clarity
- Extracting methods to split long methods into smaller, manageable ones
- Moving properties or methods between classes
- Creating constants for magic numbers or fixed values
- Promoting local variables to class variables (fields)
Unit Testing with JUnit
JUnit is a popular unit testing framework for the Java programming language.
Benefits of Unit Testing
- Facilitates easier changes by quickly detecting errors.
- Simplifies the integration of new code.
- Serves as documentation for expected behavior.
- Separates a component’s interface from its implementation.
Key JUnit Annotations
@Test: Marks a method as a test method.@Beforeand@After: Designate code to run before and after each test method, respectively.@BeforeClassand@AfterClass: Designate code to run once before and after all tests in a class, respectively.
Common Assertion Methods
assertEquals(expectedValue, actualValue)assertTrue(condition)assertFalse(condition)assertNull(object)assertNotNull(object)
