Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #21625 > unrolled thread

Re: How to break long method name into more than one line?

Started byHerman <sorsorday@gmail.com>
First post2012-03-14 13:53 -0700
Last post2012-03-15 00:07 +0000
Articles 2 — 2 participants

Back to article view | Back to comp.lang.python


Contents

  Re: How to break long method name into more than one line? Herman <sorsorday@gmail.com> - 2012-03-14 13:53 -0700
    Re: How to break long method name into more than one line? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-03-15 00:07 +0000

#21625 — Re: How to break long method name into more than one line?

FromHerman <sorsorday@gmail.com>
Date2012-03-14 13:53 -0700
SubjectRe: How to break long method name into more than one line?
Message-ID<mailman.652.1331758410.3037.python-list@python.org>
I followed the rule because it was a very good advice. For example,
def test_plus_1Plus1_2(self):
If this test fails, you immediately know that it's testing the "plus"
method, with 1  and 1 as the arguments, and expect to return 2.
Sticking this rule also means your test cases are small enough, so you
clearly know what you are testing on. Most of the time, the method
name is what you first see when your test fails. Another alternative
is to put meaningful string in each of the assert, which is probably
not practical. You are right, only people who really follow the TDD
method know the good things about it. This naming rule served me very
well.

Tests method should have meaningful name, and the advice by the book
is a meaningful one. I said it's the TDD book because I forgot the
exact title. It's actually called Test Driven: TDD and Acceptance TDD
for Java Developers. I thought it should be popular enough that most
people learned TDD may have heard it also used this naming advice, but
look like i was wrong.

> *The* TDD book? There's only one? Surely not.
>
> That rule sounds utterly impractical. I can't think of anything to
> recommend it. Like any other function, method or class, tests should have
> meaningful names, but reading the name alone should not necessarily tell
> you *everything* about the function.
>
> We have "len", not "len_sequence_or_mapping_int", and similarly it is
> perfectly reasonable to have "test_len_empty" rather than
> "test_len_emptylist_emptystr_emptyunicode_emptydict_emptyset_emptytuple_zero".
>
> I expect that naming rule was invented by either people who have heard of
> test driven development, but never actually done it, or by people so
> anally-retentive that if they make seven short car trips over an hour,
> they check the tyre pressure, oil and water seven times because "the
> manual says to check before *every* trip".
>
> No offence.
>
> My advice is to moderate the naming convention of your tests with a good
> dose of common sense and aim for names which are readable rather than
> names that contain everything including the kitchen sink. Imagine you are
> in a technical meeting with some of your fellow programmers, and need to
> ask for help with a failing test. Imagine saying the name of the test
> aloud in a sentence. Does it add clarity to the discussion, or obfuscate
> it?
>
> People's short term memory can only hold so much (allegedly "seven plus
> or minus two"), and if the name itself hits that limit, you leave nothing
> left for the rest of the sentence.
>
> http://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two
>
> Names should be practically, rather than conforming to some naming rule
> that hurts readability and obfuscates the tests.
>
>

[toc] | [next] | [standalone]


#21636

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2012-03-15 00:07 +0000
Message-ID<4f6132d8$0$29981$c3e8da3$5496439d@news.astraweb.com>
In reply to#21625
On Wed, 14 Mar 2012 13:53:27 -0700, Herman wrote:

> I followed the rule because it was a very good advice. For example, def
> test_plus_1Plus1_2(self):
> If this test fails, you immediately know that it's testing the "plus"
> method, with 1  and 1 as the arguments, and expect to return 2.

That is hardly a representative example, or you would not be asking for 
advice on splitting long method names over multiple lines.

A more relevant example might be

def 
test_alongmethodname_someargument_YouRepeatTheMethodNameForSomeReason_anotherargument_someresult
(self):


For utterly trivial examples such as testing that 1+1 == 2 nearly any 
naming scheme would be suitable. But for realistic test cases, the rule 
fails utterly.

Here is a real test case from one of my own projects: I have a project 
that defines dozens of related statistical functions, with hundreds of 
tests. Here is one test class for one function, the population variance 
(pvariance):


class PVarianceTest(NumericTestCase, UnivariateMixin):
    # Test population variance.
    # This will be subclassed by variance and [p]stdev.
    tol = 1e-11

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.func = calcstats.pvariance
        # Test data for test_main, test_shift:
        self.data = [4.0, 7.0, 13.0, 16.0]
        self.expected = 22.5  # Exact population variance of self.data.
        # If you duplicate each data point, the variance will scale by
        # this value:
        self.dup_scale_factor = 1.0

    def setUp(self):
        random.shuffle(self.data)

    def get_allowed_kinds(self):
        kinds = super().get_allowed_kinds()
        return [kind for kind in kinds if hasattr(kind, '__len__')]

    def test_main(self):
        # Test that pvariance calculates the correct result.
        self.assertEqual(self.func(self.data), self.expected)

    def test_shift(self):
        # Shifting the data by a constant amount should not affect
        # the variance.
        for shift in (1e2, 1e6, 1e9):
            data = [x + shift for x in self.data]
            self.assertEqual(self.func(data), self.expected)

    def test_equal_data(self):
        # If the data is constant, the variance should be zero.
        self.assertEqual(self.func([42]*10), 0)

    def testDuplicate(self):
        # Test that the variance behaves as expected when you duplicate
        # each data point [a,b,c,...] -> [a,a,b,b,c,c,...]
        data = [random.uniform(-100, 500) for _ in range(20)]
        expected = self.func(data)*self.dup_scale_factor
        actual = self.func(data*2)
        self.assertApproxEqual(actual, expected)

    def testDomainError(self):
        # Domain error exception reported by Geremy Condra.
        data = [0.123456789012345]*10000
        # All the items are identical, so variance should be exactly zero.
        # We allow some small round-off error.
        self.assertApproxEqual(self.func(data), 0.0, tol=5e-17)

    def testSingleton(self):
        # Population variance of a single value is always zero.
        for x in self.data:
            self.assertEqual(self.func([x]), 0)

    def testMeanArgument(self):
        # Variance calculated with the given mean should be the same
        # as that calculated without the mean.
        data = [random.random() for _ in range(15)]
        m = calcstats.mean(data)
        expected = self.func(data, m=None)
        self.assertEqual(self.func(data, m=m), expected)


(I'm a little inconsistent when choosing between camelCase and 
under_score names in my tests. My bad.)

Even with the limited examples shown there, the naming convention you 
give is utterly impractical. Most of the inputs are random (e.g. 
testDuplicate uses 20 randomly selected integers) or implementation 
details (e.g. test_equal_data takes a list of ten 42s, and returns 0, but 
that could have been thirty-five 7s, or six 1.29345e-9s, or nearly any 
other value).

Some of the tests don't even test a *specific* input and output, but 
compare that the variance of one set of data matches the variance of a 
different set of data.

> Sticking
> this rule also means your test cases are small enough, so you clearly
> know what you are testing on. 

Sticking to this rule means that you are probably missing tests that 
don't fit into the simple "arguments -> result" framework, and 
compromising the quality test suite.

If you only test the simple cases, you aren't testing the cases that are 
most likely to fail.


-- 
Steven

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web