From: Mark Woyna on
On Dec 17, 9:43 am, Veloz <michaelve...(a)gmail.com> wrote:
> Hi there
>
> I've been creating unit testing for a month or so now and have been
> trying to read/absorb as much as possible on creating code that can be
> easily tested.
>
> One conclusion I've come to is this: "In general, if class A needs to
> access class B to perform some functionality, it should know B though
> an interface, not through a class type".
>
> For testing, this allows you to mock B (even if you haven't written
> "real" implementations of B yet!) and in general it leads to more
> flexible code because A can take any class that implements B.
>
> Here's the part I'm having trouble with though: Sometimes it feels
> like the above rule leads to gratuitous creation of interfaces for no
> other reason than to make them more testable... possibly at the
> expense of more complicated and slower code.
>
> That is, I feel like I'm creating interfaces sometimes when I
> otherwise wouldn't. Is this just me or am I missing something?
>
> ..
>
> I suppose this leads to a more general question about "agile" rule of
> "program to interfaces, not to types".. Creating interfaces feels
> right to me when you know you have a responsibility/ability in your
> code that might need to be implemented in multiple spots (i.e., by
> various classes).
>
> But sometimes it seems like you have a class whose responsibilities/
> abilities are very specific to that class, and the idea of specifying
> these responsibilities as an interface, knowing fully well that the
> only one class will ever implement them, seems wrong to me..
>
> For example, if I have a class that represents a unique entity in my
> application and provides a few key methods for working with that
> entity, should I really describe those methods in an interface and
> then have this class implement that interface? (It feels strange,
> knowing that the interface wouldn't be reused.. why not just have the
> other types know this class by type and skip the interface?)
>
> I realize I'm rambling a bit here.. Any ideas on this topic would be
> welcomed
> Michael

One option that allows you to avoid interfaces is to isolate all
dependencies in protected methods, and then extend the class under
test, overriding the methods that have external dependencies with
local mock implementations.

For example,

public class A {
private B b;
public A(B aB) {
b = aB; // dependency injection

public void someMethod() {
if ( b.isValid() ) { doSomething(); }

protected void doSomething() {...}
}
}

In this example, class A has a dependency on class/interface B. First,
we refactor the class to isolate all dependent code:

public void someMethod() {
if ( isBValid() ) { doSomething(); }
}

protected isBValid() { return b.isValid(); }


Next, we derive a test class from class A, overloading the methods
with external dependencies.

public class ATest extends A {

protected isBValid() { return true; } // local mock
}

Now we can use the test class in our unit tests:

public class ATest extends TestCase {

public void test1() {
A aA = new ATest();
a.someMethod();
...
}
}

I typically define the test classes, and unit test classes as static
inner classes of the base class, as this keeps the test implementation
close to the actual code. The biggest advantage of this approach is
that it leads to much more readable code. The body of the "core"
methods do not have *any* external dependencies. They are almost
entirely business logic. The extracted methods are basically getter
methods.

This approach is particularly useful when you're using only one or two
methods from a class with many methods. It's a pain to have to create
a full-blown mock implementation when you're only using a subset of
the methods. With the approach above, you only have to override the
protected getter methods.

In a nutshell, I generally agree that one should code to an interface.
However, it's not a rule carved in stone. As you discovered, if you're
creating interfaces strictly to make unit testing easier, there are
ways around it.

Mark
From: Ed Kirwan on
Veloz wrote:

> Hi there
>
> I've been creating unit testing for a month or so now and have been
> trying to read/absorb as much as possible on creating code that can be
> easily tested.
>
> One conclusion I've come to is this: "In general, if class A needs to
> access class B to perform some functionality, it should know B though
> an interface, not through a class type".
>
> For testing, this allows you to mock B (even if you haven't written
> "real" implementations of B yet!) and in general it leads to more
> flexible code because A can take any class that implements B.
>
> Here's the part I'm having trouble with though: Sometimes it feels
> like the above rule leads to gratuitous creation of interfaces for no
> other reason than to make them more testable... possibly at the
> expense of more complicated and slower code.

There are very few goals upon which the general programming community can
whole-heartedly agree, but unnecessarily increasing software complexity is
unlikely to be one of them.

Simplicity trumps absolutely everything.

(With the possible exception of functionality.)

It's possible that a shift in encapsulation granularity might give you a
little perspective.

If you have tight, cohesive name spaces, then those name spaces will
probably be re-used in their entirety rather via the individual clumps of
classes within. Ripping an interface from a class that's private to a name
space does indeed seem like overkill.

If a class is public to the system, however, then there might be slightly
more justification in unzipping an interface from it, even if - at that
point in time - there are not multiple implementations that might animate
that interface. I wouldn't say that the primary reason in doing this is
test-related, rather to permit the possibility of re-use while allowing the
hidden innards of the name space (to which the interface gives access) to
mutate over time without affecting client name spaces.

>
> That is, I feel like I'm creating interfaces sometimes when I
> otherwise wouldn't. Is this just me or am I missing something?
>
> ..
>
> I suppose this leads to a more general question about "agile" rule of
> "program to interfaces, not to types".. Creating interfaces feels
> right to me when you know you have a responsibility/ability in your
> code that might need to be implemented in multiple spots (i.e., by
> various classes).

Copy that.

(Though I hadn't realised that our Agile friends were now claiming the
rights to that particular principle.)

>
> But sometimes it seems like you have a class whose responsibilities/
> abilities are very specific to that class, and the idea of specifying
> these responsibilities as an interface, knowing fully well that the
> only one class will ever implement them, seems wrong to me..

Again, agreed.

>
> For example, if I have a class that represents a unique entity in my
> application and provides a few key methods for working with that
> entity, should I really describe those methods in an interface and
> then have this class implement that interface? (It feels strange,
> knowing that the interface wouldn't be reused.. why not just have the
> other types know this class by type and skip the interface?)

Well, here you do seem to be describing a class public to the system; which
is fine, and your doubts over the use of an interface in this case -
despite my earlier comment - are understandable.

For what it's worth, there's another advantage to be had from only allowing
access to public classes via an interface: if you then store the interface
in a separate name space, then clients need not be affected should you
usher the original, implementing name space to a new home in your class
hierarchy. FWIW, I use this tactic often, storing all interfaces in an
interface repository, and allowing the implementing name spaces to wander
the digital tundra in search of grazing pasture; see:
http://www.edmundkirwan.com/fracdoc/frac-page10.html

But this is a miniscule point, even a matter of taste. The brushstrokes of
great software are much broader.

>
> I realize I'm rambling a bit here.. Any ideas on this topic would be
> welcomed
> Michael

--
..ed

www.EdmundKirwan.com - Home of encapsulation theory.