STUDY GUIDE · CLO 11 · CODE COVERAGE · WEEKS 14–15
Test cases and code coverage
How to write a test case as evidence for a decision, where it sits among the testing strategies, and what code coverage does and does not tell you. You practise this in the tests and the coverage step of every Python build (Assignments 3–9), and it is part of the final examination.
باختصار
هذا الدليل يغطي موضوع «تغطية الشيفرة» في توصيف المقرر، ومخرج التعلم 11: تصميم حالات الاختبار وتنفيذها في استراتيجيات الاختبار المختلفة. تتدرّب عليه في خطوة التغطية في كل بناء برمجي (الواجبات 3–9)، وهو ضمن الاختبار النهائي. اقرأ الأقسام الأربعة، ثم جرّب المثال المحلول، ثم أجب عن أسئلة المراجعة.
Reading: I. Sommerville, Software Engineering, 10th edition, Chapter 8 (Software testing): 8.1 development testing, 8.2 test-driven development, 8.3 release testing, 8.4 user testing.
1 · Testing strategies and levels استراتيجيات الاختبار ومستوياته
| Level | What it checks | Where you meet it in this course |
|---|---|---|
| Development testing · unit | One function, method or class on its own. | Every build: your test_ functions call one function. |
| Development testing · component | Several units through their interface; interface misuse and timing. | Chapter 16: the interface contract. |
| Development testing · system | The integrated system, including the interactions between components. | Chapter 20: cross-owner interaction testing. |
| Release testing | A separate team checks the system against its requirements before release; requirements-based, scenario and performance testing. | Chapter 11: statistical testing with an operational profile. |
| User testing | Alpha, beta and acceptance testing by users or the customer. | Chapter 20: staged acceptance. |
2 · Writing a test case as evidence حالة الاختبار دليلاً
In this course a test is evidence for a dependability decision: it shows that a requirement holds, that a misuse is refused, or that a changed condition is handled.
| Source of the test | What you write | Example from the builds |
|---|---|---|
| From the requirement | Turn each requirement or course check into at least one test that asserts the expected result. | Each course check in a build is a requirement test. |
| What is allowed and what is refused | Test the normal case and the case that must be refused, including missing or invalid data; check that the refusal fails safely. | A record without "loans"; loans given as text. |
| Misuse cases | Turn a misuse case into a test that the attack or misuse is refused. | Chapter 13: misuse cases become tests. |
| The changed condition | When new evidence changes a condition (STRESS), add a test for the new condition before you change the code (REFIT). | The REFIT step in Assignments 3–9. |
| Test-driven development | Write a failing test, write the code that passes it, then refactor. | Run your tests after each change in a build. |
Scope. Systematic test-design techniques, such as equivalence partitioning, boundary-value analysis, decision tables, path coverage and random or automated test generation, are the subject of a dedicated software-testing course. They are not taught or assessed in CPIT-455.
حدود الموضوع: تقنيات تصميم الاختبار المنهجية، مثل تقسيم التكافؤ وتحليل القيم الحدّية وجداول القرار وتغطية المسارات والتوليد العشوائي أو الآلي للاختبارات، موضوع مقرر مستقل في اختبار البرمجيات، ولا تُدرَّس ولا تُقيَّم في هذا المقرر.
3 · Coverage measures مقاييس التغطية
| Criterion | Definition | In this course |
|---|---|---|
| Statement (line) coverage | Share of executable statements run at least once by the tests. | The build record reports it for your own code. |
| Branch (decision) coverage | Share of decision outcomes (each if true and false; each loop entered and skipped) taken by the tests. | The build record lists every branch your tests did not take. |
What coverage does not show. Coverage tells you which code your tests ran, not whether they checked the result. Code that was never written, such as a missing check, cannot be uncovered. Treat coverage as a map of what is still untested, not as a score. Mutation testing, used in every build, asks the stronger question: would a test fail if the code were wrong?
ما لا تُظهره التغطية: التغطية تبيّن أي جزء من الشيفرة نفّذته اختباراتك، ولا تبيّن هل تحققت الاختبارات من النتيجة. والفحص الناقص الذي لم يُكتب أصلاً لا يظهر في التغطية. لذلك تستخدم البناءات اختبار الطفرات أيضاً.
4 · Coverage tools أدوات التغطية
| Language | Tool | Typical use |
|---|---|---|
| Python | coverage.py | coverage run --branch -m pytest, then coverage report -m (lists the lines not run) |
| Java | JaCoCo | Maven or Gradle plugin; HTML report of line and branch coverage |
| JavaScript | Istanbul (nyc) or c8 | nyc npm test, or c8 node --test |
| C and C++ | gcov / lcov | compile with --coverage, run the tests, then gcov or lcov |
The build in your assignment measures line and branch coverage of your own functions (not of the test_ functions) in the browser, so you do not need to install a tool.
5 · Worked example مثال محلول
The complete solution of the practice build has four tests: a normal loan, a third item, an overdue student and a broken record.
def can_borrow(student, item):
try: # line 2
loans = student["loans"] # line 3
if type(loans) is not int or loans < 0: # line 4
return False # line 5
return item["available"] is True and loans < LIMIT and student["overdue"] is False # line 6
except (KeyError, TypeError): # line 7
return False # line 8
- Lines run: the first three tests run lines 2, 3, 4 and 6; the broken-record test runs lines 2, 3, 7 and 8.
- Not covered: line 5 never runs. Statement coverage is 5 of 6 statements, and the true outcome of the
ifon line 4 is never taken. - Fix: add
test_negative_loans_are_refusedwithloans = -1and assert that the result isFalse. Run the build again: the branch is now taken. This is exactly the coverage step in Assignments 3–9.
6 · Check yourself راجع نفسك
Answer first, then open each question.
1. Does 100% statement coverage guarantee 100% branch coverage?
No. An if without an else can have every statement run by a test where the condition is true, while the false outcome is never taken. Branch coverage includes statement coverage, not the other way round.
2. Your tests reach 100% line coverage and all pass. Is the code correct?
Not necessarily. Coverage shows that code ran, not that a test checked its result. A test without an assert can run every line. That is why the builds also use mutation testing: each known faulty version must make at least one of your tests fail.
3. A requirement says: "a student with an overdue item cannot borrow." Write one test for it.
Build a student record with overdue set to True and an available item, call can_borrow, and assert that the result is False. Name the test after the requirement, for example test_overdue_student_is_refused.
4. At which testing level do you check that two components owned by different teams work together?
Component or system testing (integration). In a system of systems (Chapter 20) this is cross-owner interaction testing.
5. The coverage report lists the branch "if type(loans) is not int or loans < 0 → true" as not taken. What do you do?
Add a test whose input makes the condition true, for example loans = −1 or loans = "2", and assert that the result is False. Then run the build again and confirm the branch is now taken.
7 · For the final examination للاختبار النهائي
- Name the testing strategies and levels in Sommerville Chapter 8 and what each one checks.
- Write a test case, with its assert, for a stated requirement or a refused case.
- Define statement and branch coverage, and explain why branch coverage is stronger than statement coverage.
- Explain what coverage cannot show, and how mutation testing complements it.
- Read a short function and its tests, and name the line or branch that is not covered and a test that would cover it.
Back to the learning path · CLO 11 in the course specification