OLD | NEW |
(Empty) | |
| 1 .. Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 |
| 2 .. For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt |
| 3 |
| 4 .. _branch: |
| 5 |
| 6 =========================== |
| 7 Branch coverage measurement |
| 8 =========================== |
| 9 |
| 10 .. :history: 20091127T201300, new for version 3.2 |
| 11 .. :history: 20100725T211700, updated for 3.4. |
| 12 .. :history: 20110604T181700, updated for 3.5. |
| 13 .. :history: 20111214T181800, Fix a bug that Guido pointed out. |
| 14 |
| 15 .. highlight:: python |
| 16 :linenothreshold: 5 |
| 17 |
| 18 |
| 19 In addition to the usual statement coverage, coverage.py also supports branch |
| 20 coverage measurement. Where a line in your program could jump to more than one |
| 21 next line, coverage.py tracks which of those destinations are actually visited, |
| 22 and flags lines that haven't visited all of their possible destinations. |
| 23 |
| 24 For example:: |
| 25 |
| 26 def my_partial_fn(x): # line 1 |
| 27 if x: # 2 |
| 28 y = 10 # 3 |
| 29 return y # 4 |
| 30 |
| 31 my_partial_fn(1) |
| 32 |
| 33 In this code, line 2 is an ``if`` statement which can go next to either line 3 |
| 34 or line 4. Statement coverage would show all lines of the function as executed. |
| 35 But the if was never evaluated as false, so line 2 never jumps to line 4. |
| 36 |
| 37 Branch coverage will flag this code as not fully covered because of the missing |
| 38 jump from line 2 to line 4. This is known as a partial branch. |
| 39 |
| 40 |
| 41 How to measure branch coverage |
| 42 ------------------------------ |
| 43 |
| 44 To measure branch coverage, run coverage.py with the ``--branch`` flag:: |
| 45 |
| 46 coverage run --branch myprog.py |
| 47 |
| 48 When you report on the results with ``coverage report`` or ``coverage html``, |
| 49 the percentage of branch possibilities taken will be included in the percentage |
| 50 covered total for each file. The coverage percentage for a file is the actual |
| 51 executions divided by the execution opportunities. Each line in the file is an |
| 52 execution opportunity, as is each branch destination. |
| 53 |
| 54 The HTML report gives information about which lines had missing branches. Lines |
| 55 that were missing some branches are shown in yellow, with an annotation at the |
| 56 far right showing branch destination line numbers that were not exercised. |
| 57 |
| 58 The XML report produced by ``coverage xml`` also includes branch information, |
| 59 including separate statement and branch coverage percentages. |
| 60 |
| 61 |
| 62 How it works |
| 63 ------------ |
| 64 |
| 65 When measuring branches, coverage.py collects pairs of line numbers, a source |
| 66 and destination for each transition from one line to another. Static analysis |
| 67 of the compiled bytecode provides a list of possible transitions. Comparing |
| 68 the measured to the possible indicates missing branches. |
| 69 |
| 70 The idea of tracking how lines follow each other was from `Titus Brown`__. |
| 71 Thanks, Titus! |
| 72 |
| 73 __ http://ivory.idyll.org/blog |
| 74 |
| 75 |
| 76 Excluding code |
| 77 -------------- |
| 78 |
| 79 If you have :ref:`excluded code <excluding>`, a conditional will not be counted |
| 80 as a branch if one of its choices is excluded:: |
| 81 |
| 82 def only_one_choice(x): |
| 83 if x: |
| 84 blah1() |
| 85 blah2() |
| 86 else: # pragma: no cover |
| 87 # x is always true. |
| 88 blah3() |
| 89 |
| 90 Because the ``else`` clause is excluded, the ``if`` only has one possible next |
| 91 line, so it isn't considered a branch at all. |
| 92 |
| 93 |
| 94 Structurally partial branches |
| 95 ----------------------------- |
| 96 |
| 97 Sometimes branching constructs are used in unusual ways that don't actually |
| 98 branch. For example:: |
| 99 |
| 100 while True: |
| 101 if cond: |
| 102 break |
| 103 do_something() |
| 104 |
| 105 Here the while loop will never exit normally, so it doesn't take both of its |
| 106 "possible" branches. For some of these constructs, such as "while True:" and |
| 107 "if 0:", coverage.py understands what is going on. In these cases, the line |
| 108 will not be marked as a partial branch. |
| 109 |
| 110 But there are many ways in your own code to write intentionally partial |
| 111 branches, and you don't want coverage.py pestering you about them. You can |
| 112 tell coverage.py that you don't want them flagged by marking them with a |
| 113 pragma:: |
| 114 |
| 115 i = 0 |
| 116 while i < 999999999: # pragma: no branch |
| 117 if eventually(): |
| 118 break |
| 119 |
| 120 Here the while loop will never complete because the break will always be taken |
| 121 at some point. Coverage.py can't work that out on its own, but the "no branch" |
| 122 pragma indicates that the branch is known to be partial, and the line is not |
| 123 flagged. |
OLD | NEW |