On Tue, 25 Apr 2017 at 17:00 Terry Reedy <tjre...@udel.edu> wrote:

> On 4/25/2017 11:00 AM, Barry Warsaw wrote:
> > On Apr 24, 2017, at 09:32 PM, Ethan Furman wrote:
> >>On 04/21/2017 03:29 PM, Victor Stinner wrote:
>
> (In the context of having a patch blocked by the blind Codecov robot ...)
>
> >>> I dislike code coverage because there is a temptation to write
> artificial
> >>> tests whereas the code is tested indirectly or the code is not
> important
> >>> enough to *require* tests.
>
> While I use code coverage to improve automated unittesting, I am opposed
> to turning a usable but limited and sometime faulty tool into a blind
> robotic master that blocks improvements.  The prospect of this being
> done has discouraged me from learning the new system.  (More on 'faulty
> tool' later.)
>

It should be stated that code coverage is not a blocking status check for
merging from our perspective (the **only** required check is that Travis
pass with it's test run). The only reason Victor ran into it at a blocker
is because he tried to do a merge over his phone where GitHub apparently
prevents merging if any failing check exists, required or not (I assume
this is because reviewing code on a small screen raises the chances of
overlooking a failing check that one actually cared about).

I'm on vacation until tomorrow so I've been off of GitHub since last
Thursday, but it's possible there's already a PR out there to turn off the
status checks. If there is still no such PR I'm still fine with turning off
the status checks for Codecov.


>
> The temptation to write artificial tests to satisfy an artificial goal
> is real.  Doing so can eat valuable time better used for something else.
>   For instance:
>
>      def meth(self, arg):
>          mod.inst.meth(arg, True, ob=self, kw='cut')
>
> Mocking mod.class.meth, calling meth, and checking that the mock is
> called will satisfy the robot, but does not contribute much to the goal
> of providing a language that people can use to solve problems.
>

My assumption is that there will be a test that meth() does the right
thing, mock or not. If we provide an API there should be some test for it;
using a mock or something else to do the test is an implementation detail.


>
> Victor, can you explain 'tested indirectly' and perhaps give an example?
>
> As used here,'whereas' is incorrect English and a bit confusing.  I
> believe Victor meant something more like 'even when'.
>
> For the last clause, I believe he meant "the code change is not
> complicated enough to *require* automated unit test coverage for the
> changed line(s)".  If I change a comment or add missing spaces, I don't
> think I should be forced to write a missing test to make the improvement.
>

Agreed.


>
> A less trivial example: on IDLE's menu, Options => Configure IDLE opens
> a dialog with a font size widget that when clicked opens a list of font
> sizes.  I recently added 4 larger sizes to the tuple in
> idlelib.configdialog.ConfigDialog.LoadFontCfg, as requested, I think, by
> at least 2 people.  I tested manually by clicking until the list was
> displayed.  As I remember, I did not immediately worry about automated
> testing, let alone line coverage, and I do not think I should have had
> to to get the change into 3.6.0.
>
> That line may or may not by covered by the current minimal test that
> simply creates a ConfigDialog instance.  But this gets back to what I
> think is Viktor's point.  This minimal test 'covers' 46% of the file,
> but it only tests that 46% of the lines run without raising.  This is
> useful, but does not test that the lines are really correct.  (For GUI
> display code, human eyeballing is required.)  This would remain true
> even if all the other code were moved to a new module, making the
> coverage of configdialog the magical ***100%***.
>
> >> If it's not important enough to require tests >> it's not important
> enough to be in Python.  ;)
>
> Modules in the test package are mostly not tested. ;)
>

:) But they are at least executed which is what we're really measuring here
and I think all Ethan and I are advocating for. E.g. I don't expect
test_importlib to be directly responsible for exercising all code in
importlib, just that Python's entire test suite exercise importlib as much
as possible as a whole.


>
> If 'test' means 'line coverage test for new or changed lines', then as a
> practical matter, I disagree, as explained above.  So, in effect, did
> the people who committed untested lines.
>
> In the wider sense of 'test', there is no real argument.  Each statement
> written should be mentally tested both when written and when reviewed.
> Code should be manually tested, preferably by someone in addition to the
> author. Automated testing is more than nice, but not everything.  Ditto
> for unit testing.
>

The problem I have with just doing manual testing for things that can
easily be covered by a unit test -- directly or indirectly -- is there are
technically 85 people who can change CPython today. That means there's
potentially 85 different people who can screw up the code ;) . Making sure
code is exercised somehow by tests at least minimizes how badly someone
like me might mess something thanks to me not realizing I broke the code.


>
> Some practical issues with coverage and CodeCov:
>
> 1. A Python module is comprised of statements but coverage module counts
> physical lines.  This is good for development, but not for gating.  The
> number of physical lines comprising a statement can change without
> changing or with only trivially changing the compiled run code.  So if
> coverage is not 100%, it can vary without a real change in statement
> coverage.
>

As I said earlier, no one here is gating PRs on code coverage.


>
> 2. Some statements are only intended to run on certain systems, making
> 100% coverage impossible unless one carefully puts all system-specific
> code in "if system == 'xyz'" statements and uses system-specific
> .coveragerc files to exclude code for 'other' systems.
>

True. We could have a discussion as to whether we want to use Coverage.py's
pragmas -- e.g. `# pragma: no cover` -- to flag code as known to be
untested. Depending on how far we wanted to take this we could also set up
pragmas that flag when a test is OS-specific (I found
https://bitbucket.org/ned/coveragepy/issues/563/platform-specific-configuration
while
looking for a solution and I'm sure we could discuss things with Ned
Batchelder if we needed some functionality in coverage.py for our needs).


>
> 3. Some tests required extended resources.  Statements that are only
> covered by such tests will be seen as uncovered when coverage is run on
> a system lacking the resources.  As far as I know, all non-Windows
> buildbots and CodeCov are run on systems lacking the 'gui' resource.  So
> patches to gui code will be seen as uncovered.
>

I view 100% coverage as aspirational, not attainable. But if we want an
attainable goal, what should we aim for? We're at 83.44% now so we could
say that 80% is something we never want to drop below and be done with it.
We could up it to 85% or 90% in recognizing that there is more testing to
do but that we will never cover all Python code (all of this is
configurable in Codecov, hence why I'm asking).


>
> 4. As I explained in a post on the core-workflow list, IDLE needs the
> following added to the 'exclude_lines' item of .coveragerc.
>      .*# htest #
>      if not _utest:
> The mechanism behind these would also be useful for testing any other
> modules, scripts, or demos that use tkinter GUIs.
>
> There seems to be other issues too.
>
> > "Untested code is broken code" :)
>
> Most of CPython, including IDLE, has been pretty thoroughly tested.  And
> we have heaps of bug reports to show for it.  What's more important is
> that even code that is tested, by whatever means, may still bugs.  Hence
>   However, obscure bugs are still found.  And even correct code can be
> corrupted (repressed) by attempt fix and improve.
>
> --
> Terry Jan Reedy
> _______________________________________________
> python-committers mailing list
> python-committers@python.org
> https://mail.python.org/mailman/listinfo/python-committers
> Code of Conduct: https://www.python.org/psf/codeofconduct/
>
_______________________________________________
python-committers mailing list
python-committers@python.org
https://mail.python.org/mailman/listinfo/python-committers
Code of Conduct: https://www.python.org/psf/codeofconduct/

Reply via email to