- Abstraction
- AI Pair Programming
- Algorithm
- API
- Array
- Array methods
- Booleans
- Callback
- Class
- Class Members
- Closure
- Closure
- Code refactoring
- Comment
- Computer programming
- Conditional statements
- Constant
- Constructor
- Coupling and Cohesion
- Data types
- Debugging
- Decorator
- Dependency
- Destructuring
- Dictionary
- Enum
- Event
- Exception / Error handling
- Function
- Generic / Template
- Higher-order function
- IDE
- Immutability
- Inheritance
- Input validation
- Integer
- Interface
- Iteration patterns
- Legacy code
- Loop
- Machine learning
- Memoization
- Memory and references
- Method
- Module
- Null / Undefined / None
- Null safety / Optional values
- Object
- Object-Oriented Programming (OOP)
- Operator
- Parameter
- Parsing
- Promise and Async/Await
- Prompt Engineering
- Recursion
- Regular expression
- Return statement
- Rollback
- Runtime
- Scope
- Script
- Sequence
- Set
- Spaghetti code
- Spread and Rest operators
- State management
- String
- Switch statement
- Synchronous vs Asynchronous execution
- Syntax
- Technical debt
- Ternary operator
- Testing
- This / Self
- Tuple
- Type casting
- Type conversion
- Variable
- Vibe coding
- Webhook
PROGRAMMING-CONCEPTS
Testing: Definition, Purpose, and Examples
Testing is the process of checking whether your code works as intended. It verifies that each part of a program behaves correctly, produces the expected results, and continues to work when you introduce changes. Instead of trusting that code works, testing confirms it through repeatable, automated checks.
Every modern software team relies on testing to catch bugs early, prevent regressions, and build confidence in new features. Whether you’re writing a simple Python function or a large React application, testing is a core skill.
Why Testing Matters
Testing plays a central role across the entire development process:
- Prevents regressions: New changes don’t break existing behavior.
- Improves confidence: You can refactor knowing that tests will catch mistakes.
- Documents behavior: Tests clarify what “correct” means for each function or component.
- Encourages clean design: Code that’s testable tends to be modular and better structured.
- Saves time: A failing automated test is faster than debugging production issues.
Testing is not about mistrusting yourself — it’s about ensuring your code remains stable as it grows.
Types of Software Testing
Though testing comes in many variations, developers often focus on three foundational levels.
Unit testing
Tests the smallest pieces of your code, like functions, utilities, or React components.
Goal: Confirm that individual parts behave independently and predictably.
Integration testing
Checks how multiple pieces work together — APIs, databases, modules, or UI segments.
End-to-end (E2E) testing
Simulates real user actions in a full environment.
Goal: Ensure the entire system works from start to finish.
A healthy codebase uses a blend of these methods, not just one.
Unit Testing in JavaScript / TypeScript
Tools like Jest, Vitest, and Mocha make JavaScript testing straightforward.
Example: testing a utility function.
// toFahrenheit.ts
export function toF(c: number): number {
return (c * 9) / 5 + 32;
}
A basic test:
import { toF } from "./toF";
test("converts Celsius to Fahrenheit", () => {
expect(toF(0)).toBe(32);
});
This test checks a clear expectation and reports failure if the output changes in the future.
Unit Testing in Python (pytest)
Python’s pytest framework is known for being simple and expressive.
Python
def total(items):
return sum(items)
Test file:
Python
def test_total():
assert total([1, 2, 3]) == 6
Pytest automatically discovers test files and runs all test functions.
If behavior changes unexpectedly, pytest highlights exactly where the failure occurred.
Testing Swift Code (XCTest)
Xcode includes XCTest for testing iOS and macOS apps.
Function to test:
func greet(name: String) -> String {
return "Hello, \(name)"
}
Test:
func testGreet() {
XCTAssertEqual(greet(name: "Anna"), "Hello, Anna")
}
Swift tests integrate directly into Xcode, showing failures during development and CI pipelines.
Testing React Components
React components benefit from libraries like React Testing Library, which focuses on actual user interactions rather than implementation details.
function Welcome({ name }) {
return <h1>Hello, {name}</h1>;
}
Test:
import { render, screen } from "@testing-library/react";
import Welcome from "./Welcome";
test("renders name", () => {
render(<Welcome name="Alice" />);
expect(screen.getByText("Hello, Alice")).toBeInTheDocument();
});
This checks that the output matches what a user would see.
Mocking Dependencies
Real applications depend on APIs, databases, or external services.
Mocking replaces those dependencies with controlled versions that return predictable values.
JavaScript example:
global.fetch = () =>
Promise.resolve({
json: () => Promise.resolve({ name: "Test User" })
});
Now the test can verify logic without needing a real server.
Python with pytest:
Python
class FakeAPI:
def get_user(self):
return {"name": "Test"}
Mocking keeps tests fast and independent of external systems.
Integration Testing
Integration tests confirm that parts of the system work together properly.
Node/TypeScript example (API + logic):
test("GET /user returns user data", async () => {
const res = await request(app).get("/user");
expect(res.status).toBe(200);
expect(res.body.name).toBe("Alice");
});
This ensures that routing, controllers, and data handling all align.
Python example (FastAPI):
Python
def test_get_user(client):
response = client.get("/user")
assert response.status_code == 200
Integration tests often use mock databases or temporary test databases.
End-to-End Testing
E2E testing simulates how a user interacts with the actual app.
Common tools: Playwright, Cypress, Selenium.
Example (Playwright):
test("user can log in", async ({ page }) => {
await page.goto("/login");
await page.fill("#email", "test@example.com");
await page.fill("#password", "password");
await page.click("button[type=submit]");
await expect(page).toHaveURL("/dashboard");
});
These tests catch issues that unit tests miss — broken forms, bad routing, authentication issues, and layout problems.
Testing in SQL-Driven Applications
Databases require careful testing, but you rarely test SQL directly.
Instead, you test the code that generates or consumes SQL.
Example (testing a repository function in TypeScript):
test("findUser returns null for unknown ID", async () => {
db.query = jest.fn().mockResolvedValue([]);
const result = await findUser(999);
expect(result).toBeNull();
});
This isolates your logic from the real database while ensuring correctness.
Test Coverage and What It Really Means
Coverage tools measure how much of your code is executed by tests.
High coverage is useful, but misleading if:
- Tests don’t check meaningful assertions
- Code executes but isn’t validated
- Critical paths remain untested
Coverage is a tool, not a goal. Good tests matter more than a high percentage.
Real-World Example: Testing a Data Processing Function
Python example that validates behavior with edge cases:
Python
def average(nums):
if not nums:
return 0
return sum(nums) / len(nums)
Tests:
Python
def test_average_basic():
assert average([10, 20]) == 15
def test_average_empty():
assert average([]) == 0 # edge case
Covering normal and edge cases prevents surprises later.
Common Testing Mistakes
- Over-testing: Too many tests slow development without adding value.
- Under-testing: Missing edge cases or skipping integration paths.
- Testing implementation instead of behavior: Leads to fragile tests.
- Not isolating dependencies: Makes tests slow and flaky.
- Skipping tests for error-handling paths: These often hide the most bugs.
Healthy testing balances clarity, speed, and coverage.
Best Practices
- Write small, clear tests that validate one thing at a time
- Prefer behavior-driven assertions (“outputs should match expectations”)
- Use mocks to control unpredictable external behavior
- Include meaningful edge cases
- Keep tests fast to encourage frequent execution
- Treat tests as part of the codebase — maintain them as carefully as production code
Strong testing habits make the entire development process smoother and more reliable.
Summary
Testing is the practice of verifying that code behaves correctly and consistently. It includes unit tests for small pieces, integration tests for combined components, and end-to-end tests for real user flows. Whether you’re writing functions in Python, handling API logic in TypeScript, or building React interfaces, testing ensures stability, prevents regressions, and supports confident development. Good tests serve as documentation, safety nets, and design guides all at once.
Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.