branch.rst 4.2 KB

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