

Testing Without Interfaces - RTigger
http://rtigger.com/blog/2013/02/19/testing-without-interfaces/

======
michaelfeathers
_One of the threads I was following on twitter last week was an exchange
between a Microsoft architect and a unit tester. The tester was complaining
about the lack of interfaces around a lot of the .net classes, especially in
new features. The Microsofty countered with the increased risk of people
rolling their own implementation of critical functionality and the increased
demand on support that would produce._

It's a poor excuse, in my opinion. We have the choice to treat software the
same way that people treat hardware products. Give notice that you will not be
supported if you do things that are outside intended use. With appliances,
this is called 'voiding the warranty.'

The problem is that we have not developed a culture which accepts those sorts
of agreements yet. The closest I've seen (and I've been tracking the
testability issue for frameworks and libraries for years) is the Eclipse
notion of _soft-final_.

They used comments to indicate that you should not subclass particular
classes. They could have marked them _final_ but they chose not to in order to
support their internal development. But, the message was clear: "if you
subclass this, and a future version breaks you, it is your problem not ours."

The fact of the matter is that language-based protection mechanisms are too
coarse. They are an attempt to solve a social problem (what people are allowed
to do) with technology and there's no way to get it right consistently. Better
to leave it in the social sphere.

~~~
jbrains
"Better to leave it in the social sphere." I don't consider this some idle
philosophical stance, either. The technical solutions don't actually solve the
problem, since people work around the attempt, _and_ they create additional
problems, such as the one at the heart of this thread. I still marvel at how
common this combination is: the "solution" doesn't actually solve the problem
and creates others that wouldn't otherwise exist.

~~~
michaelfeathers
There should be a name for that generative pattern, eh?

------
ghubbard
Trying to unit test the internet is not a good idea, your life will be easier
if you refactor things and simplify a little.

    
    
      public bool StringIsEvenLength(string somestring )
      public string FetchRemoteString( string uri )
    
      public bool RemoteStringIsEvenLength(string uri)
      {
          fetched = FetchRemoteString( uri );
          if( fetched != null ) {
            return StringIsEvenLength( fetched );
          }
          throw new SomeOtherException("Didn't get a string to check the length of.");
      }
    

Now StringIsEvenLength is trivial to test. When you want to test
RemoteStringIsEvenLength

You can mock out FetchRemoteString and don't even have to use a WebClient at
all.

~~~
RTigger
That's a pretty good point, and a much better solution to the example I gave.
It'd be interesting to see FetchRemoteString as a Func<string, string>
property where you could have a default implementation (web client) and then
in your test setup you could just redefine the property to do whatever you
want.

The general point still stands though - if there was an interface, we wouldn't
have to come up with these workarounds.

------
chinpokomon
Having started my professional career as a Tester (SDET) at Microsoft, this
topic resonates with me. In my experience testers need to be more aggressive
and assertive with the code their developers have written. Obviously this
implies you've already established a good relationship with your coworkers,
but you shouldn't be afraid to tell developers that their untestable code
needs to be given a second look. It's not pleasant telling someone "their baby
looks ugly," but that is one of the responsibilities of white box testers.

Dependency Injection greatly improves the landscape. Don't instantiate
concrete classes when you can have a DI framework construct those objects for
you. This will allow you as the tester to supply the mocked objects rather
than taking the wrapper approach. It is better if as a team you've introduced
this design decision up front, but you can introduce it later for problematic
classes that need extra attention. In Java, I love using Guice for this sort
of thing, in .NET I've used Ninject in the past.

One thing that .NET has in its favor that Java doesn't is partial classes with
an internal access modifier. You can then put your test code in these partial
classes and grant them access to your assembly. This allows you to separate
your private test code hooks from your shipping code, and it prevents someone
from deriving from your class and using those test interfaces incorrectly.

This line is the problem: public WebClient client = new WebClient(); client
shouldn't be public and it shouldn't be using a concrete class. Introduce an
interface, use DI, and use internal partial classes as needed. If your
developer won't do this, find a new developer. Anyone can write code, but
writing good testable code with a clean separation of intents is something
some developers never learn, usually because no one has told them, "You're
doing it wrong."

