On Wed, 04 Jun 2008 15:55:38 +1000, Ben Finney wrote:

> Marc 'BlackJack' Rintsch <[EMAIL PROTECTED]> writes:
> 
>> On Wed, 04 Jun 2008 13:50:42 +1000, Ben Finney wrote:
>> 
>> > It seems you [alex23] have a different idea of what unit testing
>> > is for from me.
>> 
>> For me it's about finding bugs where documentation and
>> implementation disagree.
> 
> Where "documentation" is "specified externally-visible behaviour of
> the unit", I agree with this.
> 
>> And if you document private functions
> 
> By definition, "private" functions are not part of the publicly
> documented behaviour of the unit. Any behaviour exhibited by some
> private component is seen externally as a behaviour of some public
> component.

But only indirectly, and it's often harder to predict the corner cases
that might trigger bugs or to test error testing in dependent private
functions.  Private functions offer an API that's public to someone, so
they ought to be documented and tested.

>> it makes sense to me to also test if they work as documented.
> 
> If they affect the behaviour of some public component, that's where
> the documentation should be.

As I said they are public themselves for someone.

>> Because the official API relies on the correct implementation of the
>> private parts it uses under the hood.
> 
> Only to the extent that the documented behaviour of the API is
> affected. The main benefit of marking something as "not public" is
> that one *is* free to change its behaviour, so long as the public API
> is preserved.

One more reason to test the individual private functions because a change
of such a function shouldn't make it necessary to change the unit tests of
the public API.

>> One part of writing unit tests is invoking functions with arguments
>> that you think are "corner cases". For example test if a function
>> that takes a list doesn't bomb out when you feed the empty list into
>> it. Or if it handles all errors correctly.
> 
> This sounds like part of the externally-visible behaviour of the code
> unit; i.e. something that belongs in the public API. I agree that this
> is the domain of a unit test.
> 
>> If a function `f()` calls internally `_g()` and that function might
>> even call other private functions, then you have to know how `f()`
>> works internally to create input that checks if error handling in
>> `_g()` works correctly.
> 
> No, you don't need to know how it works internally; you need only know
> what guarantees it must keep for its external behaviour.

How do you know the "corner cases" then?  Often it is interesting how a
function that takes integers copes with zero, so that might be a test. 
It's easy if you test a function directly but you need to know the
internals if you must find arguments that lead to a dependent function
called with zero.  Contrived example:

def _g(i):
    return (42 / i) if i else 0

def f(x):
    return _g(x + 23)

Here ``f(-23)`` is a special corner case that should be tested somehow. 
And I think it is better tested as explicit test of `_g()` than with a
test of `f()`.  Testing for "corner cases" needs some knowledge about the
implementation, but that shouldn't be "transitive".  The tests for `f()`
should assume that `_g()` itself has promised in its documentation was
already covered by a unit test.

> If someone wants to alter the `_g()` function, or remove it entirely
> while preserving the correct behaviour of `f()`, that should have no
> effect on the external behaviour of `f()`.
> 
> That is to say, the knowledge of the "internals" of `f()` in your
> example is actually knowledge of something that should be documented
> as part of the external behaviour of `f()` — that, or it's not
> relevant to the behaviour of `f()` and shouldn't be unit tested in
> order that encapsulation is preserved.

`f()`'s documentation should mention that "it works for all integers
including -23" with -23 explicitly mentioned?

>> What do you do in such a situation? Build something from untested
>> private parts and just test the assembled piece?
> 
> Assert the corner-case behaviour of `f()`, through unit tests that
> operate on `f()` without caring about its internals.

And this way missing many potential bugs?

>> I prefer to test the private functions too. After all the private
>> functions are not private to the everybody, there *are* functions
>> that rely on them working correctly.
> 
> Then for *those* interfaces, unit tests can be devised that make
> assertions about those interfaces.

Now you lost me.  So essentially you don't test private functions unless
they are used somewhere, then they should be tested too.  As private
functions that are not used, shouldn't be there in the first place, every
function private or public should be tested, right!?

Ciao,
        Marc 'BlackJack' Rintsch
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to