views:

184

answers:

7

I have occasionally heard or read about people asserting their interfaces in a unit test. I don't mean mocking an interface for use in another type's test, but specifically creating a test to accompany the interface.

Consider this ultra-lame and off-the-cuff example:

public interface IDoSomething
{
   string DoSomething();
}

and the test:

[TestFixture]
public class IDoSomethingTests
{
   [Test]
   public void DoSomething_Should_Return_Value()
   {
        var mock = new Mock<IDoSomething>();
        var actualValue = mock.Expect(m => m.DoSomething()).Returns("value");

        mock.Object.DoSomething();
        mock.Verify(m => DoSomething());
        Assert.AreEqual("value", actualValue);
   }
}

I suppose the idea is to use the test to drive the design of the interface and also to provide guidance for implementors on what's expected so they can draw good tests of their own.

Is this a common (recommended) practice?

+13  A: 

In my opinion, just testing the interface using a mocking framework tests little else than the mocking framework itself. Nothing I would spend time on, personally.

I would say that what should drive the design of the interface is what functionality that is needed. I think it would be hard to identify that using only a mocking framework. By creating a concrete implementation of the interface, what is needed or not will become more obvious.

The way I tend to do it (which I by no means claim is the recommended way, just my way), is to write unit tests on concrete types, and introduce interfaces where needed for dependency injection purposes.

For instance, if the concrete type under test needs access to some data layer, I will create an interface for this data layer, create a mock implementation for the interface (or use a mocking framework), inject the mock implementation and run the tests. In this case the interface serves no purpose than offering an abstraction for the data layer.

Fredrik Mörk
Could you explain more?
fastcodejava
So you would be more in favor of creating a test around a concrete (perhaps semi-permanent) type, then extract the interface(s) and base type(s) from there?
HackedByChinese
@HackedByChinese: yes, something like that. I have extended my answer a bit, which perhaps sheds some more light on my reasoning.
Fredrik Mörk
A unit test should test a concrete functionality. In your example, the interface does not return "value", it returns any string. What your test really does, is verify that if you tell the mocking framework that it should return "value", then the mock does actually return "value". It's not telling you anything "useful" about the interface, or any of its concrete implementations - it passes or fail, if the mocking interface behaves the way you expect.
Mathias
+9  A: 

I've never seen anything like this but it seems pointless. You would want to test the implementation of these interfaces, not the interfaces themselves.

Matt Dearing
+1  A: 

This is good practice if there are testable black box level requirements that implementers of your interface could reasonably be expected to pass. In such a case, you could create a test class specific to the interface, that would be used to test implementations of that interface.

public interface ArrayMangler
{
    void SetArray (Array myArray);
    Array GetSortedArray ();
    Array GetReverseSortedArray();
}

You could write generic tests for ArrayMangler, and verify that arrays returned by GetSortedArray are indeed sorted, and GetReverseSortedArray are indeed sorted in reverse.

The tests could then be included when testing classes implementing ArrayMangler to verify the reasonably expected semantics are being met.

csj
What do you mean by "the functionality of an interface"?
Jørn Schou-Rode
Not meeting the contract would through a compiler error, so unit testing the contract is simply redundant.
Todd Benning
@Jørn Schou-Rode and Todd Benning. bad wording on my part. Re-wrote to clarify my thoughts. I look forward to seeing how many more downvotes I can get (so long as constructive comments continue) :)
csj
+1 for the edit. It makes perfectly sense now :)
Jørn Schou-Rode
Maybe, but wouldn't you still need to know the specifics of the implementation to be able to verify if the array was sorted correctly. I still feel like the unit tests should be specific to each implementation. If you're able to write a generic unit test for an interface, then perhaps you should consider making it an abstract base class or something of the sorts.
Todd Benning
@Todd Benning: My example has grey area. What data type is contained, and HOW is it ordered? If I had specified an array of unsigned integers, then reasonable assumptions could be made about the ordering. The underlying point I'm trying to make is, there are cases where the semantics implied by an interface are clear, and separate from the specifics of an implementation. Also, since the interface itself provides no functionality, and tests would have to be run against instances of classes implementing the interface, an abstract base class would be inappropriate.
csj
+1  A: 

In my opinion is not the way to go. A interface is created as an act of refactoring (extract interface) not TDD. So you start by creating a class with TDD and after that you extract an interface (if needed).

Rickard von Essen
I see, so you are thinking along the lines of my comment in @Fredrik Mörk answer?
HackedByChinese
@HackedByChinese Yes I do, but I think my answer was more concise.
Rickard von Essen
+1  A: 

Interfaces are about well designed contracts, not well-implemented ones. Since C# is not a dynamic language that would allow the interface to go un-implemented at runtime, this sort of test is not appropriate for the language. If it were Ruby or Perl, then maybe...

A contract is an idea. The soundness of an idea is something that requires the scrutiny of a human being at design time, not runtime or test time.

An implementation can be a "functional" set of empty stubs. That would still pass the "Interface" test, but would be a poor implementation of the contract. It still doesn't mean the contract is bad.

About all a specific Interface test accomplishes is a reminder of original intention which simply requires you to change code in 2 places when your intentions change.

mrjoltcola
A: 

The compiler itself does the verification of the interface. TDD does the validation of the interface.

You may want to check out code contracts in c# 4 as you are slightly bordering into that area in how you phrase the question. You seem to have bundled a few concepts together, and you are understandably confused.

The short answer to your question is that you've probably misheard/misunderstood it. TDD will drive the evolution of the Interface.

TDD tests the interface by verifying that coverage is achieved without involving the concrete types (the specific ones that implement the interface).

I hope this helps.

Tormod
A: 

Interfaces are about relationships between objects, which means you can't "test-drive" an interface without knowing the context it's being called from. I use interface discovery when using TDD on the object that calls the interface, because the object needs a service from its environment. I don't buy that interfaces can only be extracted from classes, but that's another (and longer) discussion.

If you don't mind the commercial, there's more in our book at http://www.growing-object-oriented-software.com/

Steve Freeman