Sealed classes - would you want them in D?

Jonathan M Davis newsgroup.d at jmdavisprog.com
Sat May 12 07:07:33 UTC 2018


On Saturday, May 12, 2018 06:42:24 rumbu via Digitalmars-d wrote:
> On Friday, 11 May 2018 at 20:22:52 UTC, H. S. Teoh wrote:
> > On Fri, May 11, 2018 at 02:04:34PM -0600, Jonathan M Davis via
> >
> > Digitalmars-d wrote:
> >> On Friday, May 11, 2018 19:45:10 rumbu via Digitalmars-d wrote:
> > [...]
> >
> >> > The first example is unit testing. Having access to the
> >> > private members of a class inside the same module is a
> >> > mistake because it breaks the idea of encapsulation. Unit
> >> > testing must be done exclusively on public members of a
> >> > class. If you are feeling the urge to test a class private
> >> > thing, there is something wrong with your class design. In
> >> > the parallel world of true OOP which D tries to avoid as
> >> > much as possible there is a saying for that: "Everytime you
> >> > test a private method, a unicorn dies".
> >>
> >> I completely disagree with this. Testing private functions can
> >> be extremely valuable for ensuring that everything within the
> >> type functions the way that it should and can often lead to
> >> much better testing of how pieces of a type work, because you
> >> have better control over what's going on at that exact point
> >> in the call chain when you're testing it directly.
> >
> > Yeah, in my own projects I have found that unittesting private
> > functions has been a life-saver in catching bugs early
> > (especially if you're writing a complex class / struct / type /
> > module with many moving parts), ensuring helper functions
> > actually work, and also building confidence that the code is
> > actually doing what you think it's doing. Testing only the
> > external API means I have to write a ton of code before a
> > single test can be run, which means a lot more places for bugs
> > to hide and a lot more time wasted trying to locate a bug
> > buried deep within several levels of function calls under the
> > public API.
> >
> > If it's true that a unicorn dies everytime I test a private
> > method, then I say, kill 'em all off, they deserve to go
> > extinct!
> >
> > (None of this negates the fact that public APIs need to be
> > thoroughly tested, of course.  Like Jonathan, I just don't see
> > how one could argue that private methods should *not* be
> > tested.)
> >
> >
> > T
>
> I never said that. Feel free to test your private methods as long
> as you want it if you think that will improve your code
> correctness. But for *me* this is a bad practice. Every time I am
> in a situation that will result in such need, I question myself
> if there is something wrong with my class design and usually I
> end with extracting that private functionality to another class
> that can be tested.
>
> Testing private functionality means that you *lock* the internal
> implementation of your class. If you decide later to change the
> implementation, your previous tests will have zero-value.
>
> On the contrary, testing public functionality of a class will
> *lock* the design and this is desirable at least from a library
> design point of view.
>
> The difference here is that D is offering you the means to code
> your stuff exactly as you want it, but the same is not true for
> my way of coding. And this is really annoying when you are doing
> TDD where the public testing of a class is in fact the definition
> of functionality and I don't want to touch by mistake any private
> member in the process.
>
> class SquareRoot
> {
>    private void someComplicatedAlgorithm { ... }
>    public void calculate() { ... someComplicatedAlgorithm() ... }
> }
>
> unittest
> {
>    //assert something about someComplicatedAlgorithm....
>    //and so on.
> }
>
>
> Let's suppose that one day I will change someComplicatedAlgorithm
> and most of the assertions will not be satisfied. That moment I
> have two options: modify all my assertions to match or completely
> delete them, hence the zero-value of them.
>
> It will not be better to limit my assertions to calculate()
> instead?

That's your choice, but even if you decided to refactor in a way that it
made sense to throw away all of the tests for a private function, at least
it was well-tested up to that point, and the tests had value as long as they
made sense. Personally, I would _much_ rather be very thorough with my tests
and then later have to seriously rework existing tests or throw them away
when I refactor than to not have thorough testing. And my experience is that
if a private function is anything other than really short and simple, having
tests for it catches bugs and improves the quality of my code, regardless of
whatever refactoring I may or may not do later.

You obviously don't have to test your private functions if you don't want
to, but if you're trying to state that testing private functions is bad
practice (and that's very much what it seemed like you were saying when you
talked about testing private functions killing unicorns), then I'm very much
going to disagree - especially in cases where the public API is relatively
simple but does a lot of stuff underneath the hood.

- Jonathan M Davis



More information about the Digitalmars-d mailing list