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