Software Testing Fundamentals โ Revision Notes
Testing knowledge signals engineering maturity โ interviewers ask about "unit vs integration testing", "black-box vs white-box", and TDD. It's especially relevant as SDET and quality-focused roles grow.
Testing levels (the pyramid)
| Level | Scope | Who |
|---|---|---|
| Unit | one component in isolation | developer |
| Integration | modules working together | developer/QA |
| System | the whole application | QA |
| Acceptance | meets business/user needs | user/business |
The test pyramid advises many fast unit tests, fewer integration tests, and few slow end-to-end tests.
Black-box vs white-box
- Black-box โ tests behaviour against the spec, with no knowledge of internal code.
- White-box โ tests internal structure/paths, driven by code coverage.
Functional vs non-functional
Functional checks what the system does; non-functional checks how well (performance, security, usability, scalability).
TDD & regression
TDD (Test-Driven Development) follows red โ green โ refactor: write a failing test, make it pass, then clean up. Regression testing re-runs tests to ensure new changes didn't break existing features.
Exam Tricks & Tips
- ๐ฏ Unit = isolated component (mocks); Integration = modules together โ the most-tested level distinction.
- ๐ฏ Black-box = spec-based, no code knowledge; White-box = structure/coverage-based โ memorise the pairing.
- ๐ฏ The test pyramid: lots of unit tests, fewer integration, fewest E2E (they're slow/brittle).
- ๐ฏ TDD cycle = red (failing test) โ green (pass) โ refactor โ a common definition question.
- ๐ฏ Regression testing guards against new changes breaking existing functionality.
- ๐ฏ Functional = what it does; non-functional = how well (performance/security/usability).
- โ Common mistake: swapping black-box and white-box โ white-box requires seeing the code; black-box does not.
Expected pattern
"Unit vs integration testing", "black-box vs white-box", "what is TDD / the red-green-refactor cycle?", "what is regression testing?", and "functional vs non-functional testing".
Quick recap
Levels: unit (isolated) โ integration (modules) โ system (whole) โ acceptance (business). Test pyramid = many unit, few E2E. Black-box (spec, no code) vs white-box (structure/coverage). TDD = red-green-refactor. Regression re-tests to catch breakage. Functional (what) vs non-functional (how well).
Software Testing Fundamentals โ Flashcards
Cover the answer, recall, then check. 12 cards on software testing.
Q1. What is unit testing?
A1. Testing an individual component/function in isolation (often with mocks), usually written by developers.
Q2. What is integration testing?
A2. Testing that multiple modules or components work correctly together.
Q3. Difference between unit and integration testing?
A3. Unit tests one component in isolation; integration tests the interactions between components.
Q4. What is black-box testing?
A4. Testing behavior against the specification without any knowledge of the internal code.
Q5. What is white-box testing?
A5. Testing based on internal code structure and logic paths, often measured by code coverage.
Q6. What does the test pyramid recommend?
A6. Many fast unit tests at the base, fewer integration tests, and few slow end-to-end tests at the top.
Q7. What is the TDD cycle?
A7. Red (write a failing test) โ Green (write code to pass it) โ Refactor (clean up while keeping tests green).
Q8. What is regression testing?
A8. Re-running existing tests after changes to ensure new code hasn't broken previously working functionality.
Q9. Functional vs non-functional testing?
A9. Functional checks what the system does (features); non-functional checks how well (performance, security, usability).
Q10. What is acceptance testing?
A10. Verifying the software meets business/user requirements โ typically performed by or for the end user.
Q11. What is system testing?
A11. Testing the complete, integrated application as a whole against its requirements.
Q12. Why keep end-to-end tests few?
A12. They are slow, brittle, and expensive to maintain; the pyramid favors fast, reliable unit tests instead.
Software Testing Fundamentals
Untested code is a liability. Testing is how teams gain confidence that software works and stays working as it changes โ and its vocabulary (unit vs integration, black-box vs white-box, the test pyramid) is common interview and exam ground.
Core idea: software testing systematically verifies that software behaves as intended and catches defects. Tests are organised by level (unit โ integration โ system โ acceptance) and by knowledge of internals (black-box = test behaviour only; white-box = test with knowledge of the code).
How it works
Beginner โ the levels of testing
- Unit test: one function/class in isolation โ fastest, most numerous.
- Integration test: multiple components working together (e.g. service + database).
- System test: the whole application end-to-end.
- Acceptance test: does it meet the user's/business requirements (often user-facing)?
Intermediate โ black-box vs white-box
- Black-box testing: based only on inputs and expected outputs, ignoring internal code. Techniques: equivalence partitioning (group inputs that behave the same) and boundary value analysis (test edges โ 0, max, off-by-one โ where bugs cluster).
- White-box testing: uses knowledge of the internal structure to design tests aiming for code coverage (statement, branch, path). It answers "did the tests execute this
ifboth ways?"
// Boundary values for "age >= 18": test 17, 18, 19 (the edges, where off-by-one hides)
Advanced โ the test pyramid, TDD, and regression
The test pyramid guides the ratio: many fast unit tests at the base, fewer integration tests in the middle, and a small number of slow end-to-end tests at the top. Inverting it (mostly slow E2E tests โ the "ice-cream cone" anti-pattern) yields brittle, slow suites. Related practices:
- TDD (Test-Driven Development): write a failing test first, then code to pass it, then refactor (red-green-refactor).
- Regression testing: re-run existing tests after changes to ensure nothing that worked broke.
- Coverage measures how much code tests exercise โ useful but not a guarantee of correctness (100% coverage can still miss logic bugs).
Worked example โ designing tests for a discount function
Function: discount(age) returns 20% off if age >= 65, else 0.
- Equivalence partitions: "senior" (age โฅ 65) and "non-senior" (age < 65) โ pick one representative each, e.g. 70 and 40.
- Boundary value analysis: test right at the edge โ 64 (no discount), 65 (discount), 66 (discount). The boundary is where an off-by-one (
>vs>=) bug would hide. - Also test invalid input: negative age, non-numeric, to check error handling.
This handful of well-chosen tests (a few partitions + boundaries) catches far more bugs than dozens of random valid ages โ demonstrating why boundary analysis and partitioning beat brute force.
Interview & exam relevance
Common asks: "difference between unit and integration testing", "black-box vs white-box testing", "what is boundary value analysis / equivalence partitioning", "what is the test pyramid", "what is TDD / regression testing", and "does 100% coverage mean bug-free?" (no). Designing test cases for a given function is a frequent practical task.
Tricks & gotchas
- Black-box = no code knowledge (behaviour); white-box = uses code structure (coverage).
- Boundary values (edges of ranges) are where bugs cluster โ always test them, not just the middle.
- High coverage โ correctness โ you can execute a line without asserting the right behaviour.
- Mnemonic: "Unit-Integration-System-Acceptance" (bottom-up levels); pyramid = many unit, few E2E.
Treating code coverage as a proxy for quality โ chasing 100% coverage and assuming the software is therefore bug-free. Coverage only measures which lines ran, not whether the tests asserted correct behaviour or covered the right edge cases. A test that executes a function but checks nothing meaningful inflates coverage while catching no bugs.
- โ- Testing levels: unit (isolated), integration (components together), system (end-to-end), acceptance (requirements).
- โ- Black-box tests behaviour from inputs/outputs; white-box uses internal structure for coverage.
- โ- Boundary value analysis and equivalence partitioning find bugs efficiently at input edges.
- โ- The test pyramid favours many fast unit tests, few slow E2E tests.
- โ- Coverage measures execution, not correctness; TDD and regression testing guard quality over time.
- โTesting verifies software behaves correctly, organised by level (unitโacceptance) and code knowledge (black-box vs white-box). Use boundary analysis and equivalence partitioning to pick high-value cases, follow the test pyramid, and remember coverage measures execution โ not correctness.
Software Testing Fundamentals โ Worked Example
Worked Example
Problem: A function classify(age) returns "minor" for age < 18, "adult" for 18 โค age โค 64, and "senior" for age โฅ 65. Design a minimal but effective set of test cases using equivalence partitioning and boundary value analysis, and classify the levels (unit vs integration) and approaches (black-box vs white-box) involved.
def classify(age):
if age < 18: return "minor"
elif age <= 64: return "adult"
else: return "senior"
Solution:
Equivalence partitioning divides inputs into classes that should be treated identically, so testing one value per class represents the whole class. Here the valid partitions are:
- P1: age < 18 โ "minor"
- P2: 18 โค age โค 64 โ "adult"
- P3: age โฅ 65 โ "senior"
Plus invalid partitions (negative or absurd ages) if the spec forbids them.
One representative each: classify(10)="minor", classify(40)="adult", classify(70)="senior".
Boundary value analysis targets the EDGES of partitions, where off-by-one bugs cluster (e.g. < vs โค). Test just inside and just outside each boundary:
- Around 18: age 17 โ "minor", age 18 โ "adult". (Catches a wrong < vs โค.)
- Around 64/65: age 64 โ "adult", age 65 โ "senior".
So the boundary cases {17, 18, 64, 65} exercise the exact comparisons the code makes. A tester who only used 10/40/70 would miss a bug where the code wrote age <= 18 (misclassifying 18 as minor); the boundary tests 17 and 18 catch it.
Minimal effective suite: {10, 17, 18, 40, 64, 65, 70} โ one per partition plus each boundary pair.
Levels and approaches:
- These tests target one function in isolation โ unit testing. Testing how classify integrates with a larger registration workflow (DB, UI) would be integration testing; the whole system end-to-end is system testing.
- Deriving cases from the SPEC (partitions/boundaries) without reading the code is black-box testing. Deriving cases to cover every branch/statement by inspecting the code (e.g. ensuring both the if and elif and else lines execute โ branch coverage) is white-box testing. A thorough plan uses both: black-box for behaviour, white-box to confirm coverage.
Answer: Test one value per equivalence class (10, 40, 70) and each boundary pair (17/18 and 64/65), giving {10,17,18,40,64,65,70}. The boundaries catch off-by-one (< vs โค) errors partition testing alone would miss. These are unit tests; deriving them from the spec is black-box, while ensuring every branch runs is white-box.
- โ- Equivalence partitioning tests one representative per input class; boundary value analysis tests the edges where off-by-one bugs hide.
- โ- Combine both: partitions for coverage of behaviour, boundaries for the exact comparison operators.
- โ- Levels: unit โ integration โ system; approaches: black-box (from the spec) vs white-box (from the code, e.g. branch coverage).