|
| 1 | +Debugging guide |
| 2 | +=============== |
| 3 | + |
| 4 | +This section is supposed to provide hints on what to check if |
| 5 | +pytest-dependency does not seem to behave as expected. |
| 6 | + |
| 7 | +Example |
| 8 | +------- |
| 9 | + |
| 10 | +We consider the following example in this guide: |
| 11 | + |
| 12 | +.. literalinclude:: ../examples/debugging.py |
| 13 | + |
| 14 | +This example contains several cases where the presumably intended |
| 15 | +behavior of the code differs from what happens in practice. We will |
| 16 | +show below how diagnostic tools in pytest may be used to unravel the |
| 17 | +discrepancies. The results that may (or may not) be surprising |
| 18 | +include: |
| 19 | + |
| 20 | ++ The test method `test_c` in class `TestClass` depending on `test_b` |
| 21 | + is run, although the test method `test_b` fails. |
| 22 | + |
| 23 | ++ All instances of `test_colors` succeed. Yet `test_multicolored` |
| 24 | + that only depends on `test_colors` is skipped. |
| 25 | + |
| 26 | ++ Similarly `test_alert` depending only on `test_colors[Color.RED]` is |
| 27 | + skipped, although `test_colors` with the parameter value `Color.RED` |
| 28 | + succeeds. |
| 29 | + |
| 30 | ++ `test_k` depending only on `test_b` is skipped, although `test_b` |
| 31 | + succeeds. |
| 32 | + |
| 33 | ++ Same with `test_m` depending only on `test_b` is skipped. |
| 34 | + |
| 35 | ++ `test_o` depending only on `test_h` is skipped, although `test_h` |
| 36 | + succeeds. |
| 37 | + |
| 38 | ++ `test_q` depending only on `test_p` is skipped, although `test_p` |
| 39 | + succeeds. |
| 40 | + |
| 41 | ++ `test_r` is run, although `test_a` fails. |
| 42 | + |
| 43 | ++ `test_s` depending only on `test_l` is skipped, although `test_l` |
| 44 | + succeeds. |
| 45 | + |
| 46 | +Diagnostic tools |
| 47 | +---------------- |
| 48 | + |
| 49 | +There are different ways to request diagnostic output from pytest. We |
| 50 | +will discuss how they may be used to better understand the behavior of |
| 51 | +pytest-dependency. |
| 52 | + |
| 53 | +pytest summary |
| 54 | +.............. |
| 55 | + |
| 56 | +You can request a short summary from pytest including information on |
| 57 | +skipped tests using the ``-rs`` `command line option`__: |
| 58 | + |
| 59 | +.. literalinclude:: ../examples/debugging-summary.out |
| 60 | + |
| 61 | +This summary indicates if a test has been skipped by pytest-dependency |
| 62 | +in the first place. In the present example, the summary hints that |
| 63 | +`test_k` has been skipped due to another reason, unrelated to |
| 64 | +pytest-dependency. If the test has been skipped by pytest-dependency, |
| 65 | +the summary displays the name of the missing dependency. |
| 66 | + |
| 67 | +.. __: https://docs.pytest.org/en/stable/usage.html#detailed-summary-report |
| 68 | + |
| 69 | +Verbose pytest output |
| 70 | +..................... |
| 71 | + |
| 72 | +A list of all tests with their respective outcome will be displayed if |
| 73 | +you call pytest with the ``--verbose`` command line option: |
| 74 | + |
| 75 | +.. literalinclude:: ../examples/debugging-verbose.out |
| 76 | + |
| 77 | +The verbose listing is particular useful, because it shows the pytest |
| 78 | +node id for each test, which is not always obvious. As explained in |
| 79 | +Section :ref:`names`, this node id is the basis to form the default |
| 80 | +test name that need to be used to reference the test in the |
| 81 | +dependencies. |
| 82 | + |
| 83 | +From this list we can understand why `test_multicolored` has been |
| 84 | +skipped: it depends on `test_colors`. But `test_colors` is |
| 85 | +parametrized and thus the parameter value is included in the node id. |
| 86 | +As a result, a dependency by the name `test_colors` can not be found. |
| 87 | +The same thing happens in the case of `test_s`: it depends on |
| 88 | +`test_l`, but the latter uses a parametrized fixture, so it indirectly |
| 89 | +takes a parameter value and that value must be included in the |
| 90 | +reference for the dependency. |
| 91 | + |
| 92 | +In the case of `test_alert`, the parameter value is included in the |
| 93 | +dependency `test_colors[Color.RED]`. But in the node id as displayed |
| 94 | +in the verbose list, that test appears as `test_colors[RED]`. Note |
| 95 | +that `class Color` overrides the string representation operator and |
| 96 | +that affects how the parameter value appears in the node id in this |
| 97 | +case. |
| 98 | + |
| 99 | +The verbose list also displays the execution order of the tests. In |
| 100 | +the present example, this order differs from the order in the source |
| 101 | +code. That is the reason why both instances of `test_q` are skipped: |
| 102 | +they are executed before the dependency `test_p`. So the outcome of |
| 103 | +the latter is yet unknown at the moment that the dependency is |
| 104 | +checked. |
| 105 | + |
| 106 | +Logging |
| 107 | +....... |
| 108 | + |
| 109 | +pytest-dependency emits log messages when registering test results and |
| 110 | +when checking dependencies for a test. You can request these log |
| 111 | +messages to be displayed at runtime using `log command line options`__ |
| 112 | +in the pytest call. Beware that this may produce a large amount of |
| 113 | +output, even for medium size test suites. We will present only a few |
| 114 | +fragments of the output here. Consider the start of that output, |
| 115 | +covering the first test `test_a`: |
| 116 | + |
| 117 | +.. literalinclude:: ../examples/debugging-logging.out |
| 118 | + :end-before: debugging.py::test_b |
| 119 | + |
| 120 | +It is shown how the test outcome for each of the three test phases |
| 121 | +(setup, call, and teardown) is registered in pytest-dependency. It is |
| 122 | +also shown which name is used to register the test outcome depending |
| 123 | +on the scope. |
| 124 | + |
| 125 | +Considering the relevant fragments of the output, we can check why |
| 126 | +`TestClass::test_c` is not skipped: |
| 127 | + |
| 128 | +.. literalinclude:: ../examples/debugging-logging.out |
| 129 | + :lines: 20-31,86-116 |
| 130 | + |
| 131 | +The dependency `test_b` is checked in module scope. If that |
| 132 | +dependency was meant to reference the method of the same class, it |
| 133 | +would either need to be referenced as `test_b` in class scope or as |
| 134 | +`TestClass::test_b` in module scope or as |
| 135 | +`debugging.py::TestClass::test_b` in session scope. The way it is |
| 136 | +formulated in the example, it actually references the test function |
| 137 | +`test_b`, which succeeds. |
| 138 | + |
| 139 | +A similar case is `test_m`: |
| 140 | + |
| 141 | +.. literalinclude:: ../examples/debugging-logging.out |
| 142 | + :lines: 20-31,264-274 |
| 143 | + |
| 144 | +The dependency `test_b` is checked in session scope. There is no test |
| 145 | +that matches this name. If that dependency was mean to reference the |
| 146 | +test function `test_b` in the example, it would either need to be |
| 147 | +referenced as `debugging.py::test_b` in session scope or as `test_b` |
| 148 | +in module scope. |
| 149 | + |
| 150 | +A slightly different situation is given in the case of `test_o`: |
| 151 | + |
| 152 | +.. literalinclude:: ../examples/debugging-logging.out |
| 153 | + :lines: 190-201,276-286 |
| 154 | + |
| 155 | +In the :func:`pytest.mark.dependency` marker for `test_h` in the |
| 156 | +example, the name is overridden as `h`. The outcome of that test is |
| 157 | +registered using that name. It can thus not be found by the name |
| 158 | +`test_h`. |
| 159 | + |
| 160 | +Considering the case of `test_r`: |
| 161 | + |
| 162 | +.. literalinclude:: ../examples/debugging-logging.out |
| 163 | + :lines: 300-310 |
| 164 | + |
| 165 | +That test has no dependencies. The error in the example is that the |
| 166 | +:func:`pytest.mark.dependency` marker is applied twice to the test. |
| 167 | +That doesn't work in pytest, only the last invocation is effective. |
| 168 | +As a result, the second invocation setting a name, effectively clears |
| 169 | +the dependency list that was set in the first invocation. |
| 170 | + |
| 171 | +.. __: https://docs.pytest.org/en/stable/logging.html#live-logs |
0 commit comments