The Object Quote Pattern for Testability of Components with Dependencies

I hereby introduce a very simple no-configuration pattern for making components with dependencies unit testable. Object Quote competes with existing solutions for testability of components with dependencies and is intended to be the simplest possible solution. This will make most sense if you already understand the problem of unit testing components and classes with dependencies.

Existing Patterns for Unit Testability

  • Dependency Injection or Service Location use a DI Container or a Service Locator for runtime configurability. As a side effect, they also provides a solution, albeit rather heavyweight, for test-time mockability
  • The Humble Object Pattern is an approach for codebases built without DI or service locator. A class with dependencies is refactored into two classes, one of which sets up the dependencies on the other, which contains the meat (or logic) of the class. The class containing the logic is then testable.

Neither of these are cost-free. Dependency Injection requires a framework and is best considered as an application-wide architectural pattern that should be used when runtime configuration is required. In that sense it is overkill for most bespoke code where you don't need to choose at runtime between multiple implementations for an interface, and all you want is test-time mockability.

The humble object is effectively a proposal to rewrite code, albeit minimally. So it has a significant cost to it; and the end result is slightly more complex than the original.

The Object Quote Pattern

is very simple. It requires no framework, and can be applied to existing code for virtually no startup cost.

  1. Merrily write (or read, if it's already written) your code with hard coded dependencies.
  2. Uncouple the dependencies by quoting the hard-coded references with a "Soq" - a simple object quoter.
  3. In your unit tests, configure the Soq as a Moq Soq.

Behold. You now have decoupled, testable code. Thus:

public class MyClassThatDependsonSomething
{
	public SomeDependency  D1 { get; set; }

    public MyClassThatDependsonSomething()
    {
        D1 = Soq.Quote( new SomeDependency() );
    }
}

[TestFixture]
public class TestExampleCode
{
    [Test]
    public void Test_something_with_dependencies()
    {
        //Arrange
        SomeDependency dummy = new Mock<SomeDependency>().Object;

        var mockSoq = new Mock<Soq>();
        mockSoq.Setup(soq => soq.QuoteImplementation<SomeDependency>(It.IsAny<SomeDependency>()))
                .Returns(dummy);
        Soq.ConfigureForTest(mockSoq.Object);

        // Act
        var myClass = new MyClassThatDependsonSomething();
        var result = myClass.D1;

        //Assert
        Assert.AreSame<SomeDependency>(dummy, result);
    }
}

How it works

By default the Soq just returns the object given it.
But when configured for test, the Soq is implemented by your MoqSoq, which returns whatever you've configured it to.

Voila. Testable code with no framework needed and no extensive refactoring of existing codebase. You get started with TDD even on legacy code with minimal overhead.

Get the code and a couple of example tests from https://github.com/xcarroll/Soq. Or copy and paste the source -- just 12 lines of actual code  -- from below.

The Soq Class

On Github: https://github.com/xcarroll/Soq/blob/master/Soq.cs

using System;
public class Soq
{
        private static Soq instance = new Soq();

        public static T Quote<T>(T instantiatedDependency)
        {
            return instance.QuoteImplementation<T>(instantiatedDependency);
        }

        public virtual T QuoteImplementation<T>(T dependency)
        {
            return dependency;
        }

        public static void ConfigureForTest(Soq testSoq)
        {
            if (!ConfigurationIsEnabled)
            {
                throw new InvalidOperationException(
                 "Test configuration is not enabled.");
            }
            instance = testSoq ?? new Soq();
        }
        public static bool ConfigurationIsEnabled { get { return true; } }
}

Highly Unlikely — The Mark of the Beast Bug

In 1991, amongst a series of theorems about rounding in floating point arithmetic calculations, the author parenthetically noted that rounding a number to 53 significant digits, and then rounding it again to 52 significant digits, might produce a different answer compared to when you do the rounding to 52 digits all in one go. He all but apologised for the parenthesis, noting it was "highly unlikely to affect any practical program adversely."

19 years and 10 months later a researcher discovered that the "Mark of the Beast Bug" could freeze almost any computer in the world, and that millions of webservers could be taken down by it almost at the touch of a button — because of an error when rounding a very very small number, first to 53 significant digits, and then to 52.

Science and the touch of celebrity fallacy

Science is great, and when something's great, this often results in enthusiastic proclamation of it as the One True Answer to pretty much anything. Which is unfortunate because science isn't. Not all true knowledge is scientific knowledge, on the contrary, scientific knowledge is only a small fraction of what we know.

Most of our daily lives run on very un-scientific but still knowledgeable questions and answers, such as 'what did you have for breakfast?' and 'what's the news this morning?' These are not questions which can be addressed by a scientific methodology because science is largely about hypothesis and repeatable experiments and there are no repeat experiments for one-off events such as what you were chomping at 8:02 this morning. These questions are answered simply by observing (looking, listening, smelling, etc.), an activity that science crucially depends on but which has been in active use since long before anyone thought of science. They could also be answered by asking someone who knows, which is probably our number one source of knowledge throughout our whole life. But that isn't at all scientific, even when it's a scientist whom you're asking. Even when you're asking a 'scientific' question. But if you go and set up the experiment for yourself, that's science.

You may be tempted to think that 'what I ate for breakfast' can be scientifically analysed by shipping you off to a forensic lab for analysis of your stomach contents. And this is what I mean by the "touch of celebrity" fallacy. Because labs are full of sciencey things like test tubes and white coats and mass spectrometers, we somehow feel that whatever information comes out of such a lab has the aura of science about it; it's scientifically proven.

This is a mistake.

Yes, a lot of science did go into developing mass spectrometers, and test tubes are often used by scientists. A forensic examination of your stomach is in that sense 'applied science', putting to use the body of knowledge acquired by the scientific method. But the experiment of you eating breakfast this morning was a one-off. In that sense the forensic analysis is no more scientific than a mate poking their fingers down your throat so that they can then carefully inspect your stomach contents on the table.

Not all true empirical knowledge is science. Sometimes it's just stuff you know. I had pancakes for breakfast this morning. I know because I was there.