Avoid Testing Implementation Details, Test Behaviours

Every so often I return to Kent Beck’s Test-Driven Development. I honestly believe it to be one of the finest software development books ever written. What I love about the book is its simplicity. There is a sparseness to it that decieves, as though it were a lightweight exploration of the field. But continued reading as you progress with TDD reveals that it is fairly complete in its insights. Where later works have added pages and ideas, they have often lessened the technique, burdening it with complexity, born of misunderstandings of its power. I urge any of you who have practiced TDD for a while to re-read it regularly

For me one of the key ideas of TDD that is often overlooked is expressed in the cycle or Red, Green, Refactor. First we write a failing test, then we implement as quickly and dirtily as we can, and then we make it elegant. In this blog post I want to talk about some of the insights of the second and third steps that get missed. (Although you should remember the first step: tests don’t have tests so you need to prove them).

A lot of folks stall when they come to implement, because they try to implement well, thinking about good OO, SOLID patterns etc. Stop! The goal is to get green as soon as possible. Don’t try to build a decent solution at this point, just script out the quickest solution to the problem you can get too. Cut and Paste if you can, copy algorithms from CodeProject or StackOverflow if you can.

From Test-Driven Development

Stop. Hold on. I can hear the aesthetically inclined among you sneering and spitting. Copy-and-paste reuse? The death of abstraction? The killer of clean design?

If you’re upset, take a cleansing breath. In through the nose … hold it 1, 2, 3 … out through the mouth. There. Remember, our cycle has different phases (they go by quickly, often in seconds, but they are phases.):

1 Write a test.

2. Make it compile.

3. Run it to see that it fails.

4. Make it run.

5. Remove duplication.”

It’s that final step (which is our refactoring step) in which we create Clean Code. Not before, but after.

“Solving “clean code” at the same time that you solve “that works” can be too much to do at once. As soon as it is, go back to solving “that works,” and then “clean code” at leisure.”

Now there is an important implication here that is often overlooked. We don’t have to write tests for the classes that we refactor out through that last step. They will be internal to our implementation, and are already covered by the first test. We do not need to add new tests for the next level – unless we feel we do not know how to navigate to the next step.

From Test-Driven Development again:

“Because we are using Pairs as keys, we have to implement equals() and hashCode(). I’m not going to write tests for these, because we are writing this code in the context of a refactoring. If we get to the payoff of the refactoring and all of the tests run, then we expect the code to have been exercised. If I were programming with someone who didn’t see exactly where we were going with this, or if the logic became the least bit complex, I would begin writing separate tests.”

Code developed in the context of refactoring does not require new tests! It is already covered, and safe refactoring techniques mean we should not be introducing specualtive change, just cleaning up the rough implementation we used to to green. At this point further tests help you steer (but they come at a cost)

The outcome of this understanding is that a test-case per class approach fails to capture the ethos for TDD. Adding a new class is not the trigger for writing tests. The trigger is implementing a requirement. So we should test outside-in, (though I would recommend using ports and adapters and making the ‘outside’ the port), writing tests to cover then use cases (scenarios, examples, GWTs etc.), but only writing tests to cover the implementation details of that as and when we need to better understand the refactoring of the simple implementation we start with.

A positive outcome from this will be that much of our implementation will be internal or private, and never exposed outside our assembly. That will lower the coupling of our solution and make it easier for us to effect change.

From Test-Driven Development again:

“In TDD we use refactoring in an interesting way. Usually, a refactoring cannot change the semantics of the program under any circumstances. In TDD, the circumstances we care about are the tests that are already passing.”

When we refactor we don’t want to break tests. If our tests know too much about our implementation, that will be difficult, because changes to our implementation will necessarily result in us re-writing tests – at which point we are not refactoring. We would say that we have over-specified through our tests. Instead of assisting change, our tests have now begun to hamper it. As someone who has made this mistake, I can vouch for the fact that it is possible to write too many unit tests against details. If we follow TDD as originally envisaged though, the tests will naturally fall mainly on our public interface, not the implementation details, and we will find it far easier to meet the goal of changing the impementation details (safe change) and not the public interface (unsafe change)

Of course, this observation, that this idea has been overlooked by many TDD practitioners, formed the kernel of Dan North’s original BDD missive and is why BDD focused on scenarios and outside-in for TDD

Posted in ATDD, BDD, SOLID, STDD, TDD, xUnit | 18 Comments

Why CRUD might be what they want, but may not be what they need

A brief history of CRUD

The Rolling Stones once sung:

“You can’t always get what you want, But if you try sometimes, well you just might find, You get what you need”

I think the same is true of CRUD. Our users seem to ask for it and we blindly agree to their wishes and build it; however, its regularly not what they need.

The File Store

When computers first arrived the early commercial use was to try and remove the need for paper files. Some of us may be old enough to remember that offices has filing departments with staff, where when we began a piece of work we went to get the records that the company had on that customer, or policy, or project. There were problems with this approach: file stores took up a lot of space, and the mangement of paper based records, particulary archival material is expensive; often, someone else had the file out, buried on their desk, and it was not always clear who – an early form of pessimistic concurrency control – which often stopped you responding to requests; files were only as useful as the discipline of maintaing them, and keeping them in order – searching was difficult within a file if it was not ordered and there was no idea of seaching the file store itself.

So it was natural when we began to think about ways in which computers could help in the workplace to think about electronic filing systems. We would record the data around the customer, policy, or project on an electronic form instead of a paper one and the computer could store it for us. We saved paper, we saved staff, we saved time, and we added new functionality such as the ability to search.

The UIs that we designed were optimized to enter data. After all there was a lot of data to enter just to catch up on. The essential questions for UX design became tab order or number of clicks – just how fast could we enter data. We wanted bulk data entry grids, and forms that mirrored our paper based forms, because that was what we needed to get out of the physical filing store and into our electronic store

Throughout the paper told us what to do and the process was built around the form. The form was passed from person to person. Stickers attached to the form, or boxes on the file defined the workflow. The paper-trail was the business process. Indeed, early analysis techniques simply followed the paper trail. Initial systems just followed the existing paper based process. Someone took the paper, the insurance application form, and type it in to the terminal. Then a batch run moved the record to the next step, so the next person in line could perform the same step that they had at the computer.

But no one really thought of this workflow as something the computer could handle. We just did handoffs the same way we did with paper. Indeed we sometimes used paper as the ‘token’ that we passed around for the workflow and told you that you needed to enter the system and do some work. Or, later we became more sophisticated, and used email to do the same thing.

And for this perspective – the electronic filing store – Create, Read, Update, and Delete (CRUD) was the paradigm we needed. It described the lifecycle of a paper file perfectly and with our goal to automate that physical file store it was a capable model – or so it seemed.

Brave New World

Users tend to create electronic documents today. There is less paper. Inputs come from phone, email, the consumer directly accessing a web-based interface. Removing the phsyical file store is no longer behind the business case to provide IT systems. We no longer want to remove the old filing room and its associated clerks. Of course we might want to move away from our new shadow IT world of documents on shared drives and Excel spreadsheets.

The business goals around automation have changed too. To obtain the savings that justify the cost of IT savings, we want to enable smaller numbers of people to carry out the tasks formally done by many through not just electronic filing but through business process automation.

But once we shift the goals away from data entry to process automation, the shape of our architecture changes too. Less of the value comes from data entry today. It comes from providing a key business differentiator that allows us to outperform the competition in service, control of costs, management of supply chain, enabling new business models through disintermediation etc.

CRUD – a model for removing the old file store is less useful as a paradigm when we come to think about analysing and architecting a response to this kind of business process.

Think about how we force users to interact under a CRUD paradigm. They have procedures written in a manual, a checklist for the process. They have to edit this page,then edit that page etc. The system consists of CRUD screens where the users do the data entry. People run their workflow using email. Business process is the preserve of a priesthood who maintain their position by understanding ‘how things are done here’.

The problem here is that the behavior is not captured in the system, it is captured in the manual at best, more likely in the oral transmission of process from one worker to another. The business understands that it has workflow and behavior – they defined process with copies of memos, forms etc. We have not removed those steps by automating them, we have just  given them electronic forms. Pejoratively we are little better than the shadow IT offering written in Access; why engage an IT expert at all for that, all you do is add cost.

Much of the issue here is sheer laziness on our part. When I see tweets and blog posts saying: most business apps are CRUD, I hear, “we don’t want to work with the business to show them what IT could do for them”. Part of the reason is because it requires little skill to model CRUD; modelling business process is harder – but that is where the value lies. Think of early software development approaches that began with modeling the data, and then identified processes to act on that data. Is it any wonder we built CRUD based systems if we started by thinking about data. Data Flow diagrams, Process diagrams. These were the cornerstones of how we thought about the design phase of the software lifecycle and we have failed to escape from it. However, for our users recording data itself is rarely the end goal any more, completion of a business process is the goal.

Now sure, in some cases we might still have CRUD, for some kinds of reference data, and I’m sure a lot of people will respond to this with straw men of CRUD only applications. But be careful. In a lot of cases the customer thinks about records management, and they don’t know you could help them with processing, business rules, workflow (or are frightened of what that might mean for their jobs). Anywhere where there is a process in someone’s head, a word document, or excel spreadsheet that says, when this happens, you need to go into this page and fill in these values on the form, you have behavior, or intent that could and should be captured.

Let’s take a simple example: changing the state of a purchase order. What we tend to be saying is: the workflow for this process has reached a certain point and so it can move into this state. We can immediately see that we must have a number of things for this to occur: the purchase order must have some data that we need to validate it; we can also see that a number of things may be predicated on this occurring: we need to send the order to fulfilment, we need to begin the billing process etc. So this act, completing a purchase order, has both a workflow or business process and rules. A CRUD based approach to design tends to encourage us to leave these outside the system, with the user, in some set of manual checks or switching between parts of the application. What we want to look at is: is this process something we could automate, could the workflow and rules live in the system?

Of course a traditional objection to putting workflow and rules ‘in the system’ is that they can change. This causes some folks to suggest that they ought to be left out.

Unfortunately in the typical business this means that a given named person Alice, Mary or Bob is the person that understands how to drive the process, and is mission critical to the success of the enterprise. If they get hit by a bus its all over, and they can pretty much ask for a raise whenever they like, because we can’t afford to lose them. Process diagrams often end up with a stick figure which imply that ‘Alice does her magic’. Often that person is uncommunicative and secretive about the process – to ensure that they remain essential to the business. When they are absent, things fall apart.

No business really wants that.

And the reality is that we have plenty of options we can use to make workflow and rules more configurable – though we need to look at the tradeoffs between the cost to change the app against using a rules engine or workflow engine carefully by understanding the amount of likely change.

Enter Tasks: What to you want to do today.

We need to drop the focus on CRUD and move to a focus on tasks: what is it that the user wants to accomplish, and how can we help them accomplish that?

Let’s think about the case of a family doctor. In an appointment they tend to take the patient’s history, diagnose the illness, and prescribe a course of treatment. Now, in the UK the paper based way to achieve this used to be the Lloyd George envelope. Simply replicating the functionality of the Lloyd George envelope using a CRUD approach would give us screens for entering consultation notes, prescriptions… But there is a lot more we could do to help. If we treat diagnosis as a task, then we ought to consider searching previous medical history to see if anything shows up related to the patient’s complaint that may be of concern. There may be guidelines for these symptoms that we should be following to check that we are not missing illnesses like meningitis. When we prescribe we can list common drugs for the illness, and look for incompatibility with drugs that the patient is currently being prescribed in a drugs database. That may lead to us offering further advice, for example if the patient is using the contraceptive pill and we prescribe them antibiotics.

Or perhaps consider an on line retailer where the customer can go in and change their account details. If the customer changes their address, we might want to prompt the customer for in-flight orders and ask where they want them to be delivered – the old address or the new address.

Ask yourself the question: am I thinking about the intent of what the user wishes to accomplish?

The grid is particularly dangerous ground in this regard. It is rare that you can capture intent through a grid. if you are using a grid you are probably not focused on a task but on CRUD

Greg Young has a great discussion on the Task-based UI. It is one of the building blocks in a journey towards understanding the why of CQRS

Posted in Uncategorized | 23 Comments

Why use the command processor pattern in the service layer

Using a Command Processor

When we think about a layered or hexagonal architecture it is common to identify the need for a service layer. The service layer both provides a facade over our domain layer to applications – acting as an API definition – and contains the co-ordination and control logic for orchestrating how we respond to requests.

One option to implement this is the notion of a service as a class:


public class MyFatDomainService
{
    public void CreateMyThing(CreateMyThingCommand createMyThingCommand)
    {
        /*Stuff*/
    }

    public void UpdateMyThingForFoo(FooCommand fooHappened)
    {
       /*Other Stuff*/
    }

     public void UpdateMyThingForBar(BarCommand barHappened)
     {
        /*Other Stuff*/
     }

     /*Loads more of these*/
}

Another option is to use the command processor pattern. There are some keys to understanding the choice to use a command processor to implement your service layer.

The Interface Segregation Principle states that clients should not be forced to depend on methods on an interface that they do not use. This is because we do not want to update the client because the interface changes to service other clients in a way that the client itself does not care about. Operation script style domain service classes force consumers (for example MVC controllers) to become dependent on methods on the domain service class that they do not consume.

Now this can be obviated by having the domain service implement a number of interfaces, and hand to its clients interfaces that only cover the concerns they have. With application service layers this naturally tends towards one method per interface.


public interface ICreateMyThingDomainService
{
    void CreateMyThing(CreateMyThingCommand createMyThingCommand);
}

public interface IUpdateMyThingForFooDomainService
{
    void UpdateMyThingForFoo(FooCommand fooHappened);
}

public interface IUpdateMyThingForBarDomainService
{
   void UpdateMyThingForBar(BarCommand barHappened);
}

public class MyFatDomainService : ICreateMyThingDomainService, IUpdateMyThingForFooDomainService, IUpdateMyThingForBarDomainService
{
   public void CreateMyThing(CreateMyThingCommand createMyThingCommand)
  {
      /*Stuff*/
   }

   public void UpdateMyThingForFoo(FooCommand fooHappened)
  {
      /*Other Stuff*/
  }

   public void UpdateMyThingForBar(BarCommand barHappened)
   {
      /*Other Stuff*/
    }

/*Loads more of these*/

}

Now the Single Responsibility Principle suggests that a class should have one and only one reason to change. All these separate interfaces begin to suggest that a separate class might be better for each interface, to avoid updating a class for concerns that it does not have.


public interface ICreateMyThingDomainService
{
    void CreateMyThing(CreateMyThingCommand createMyThingCommand);
}

public class CreateMyThingDomainService : ICreateMyThingDomainService
{
    public void CreateMyThing(CreateMyThingCommand createMyThingCommand)
    {
       /*Stuff */
    }
}

public interface IUpdateMyThingForFooDomainService
{
    void UpdateMyThingForFoo(FooCommand fooHappened);
}

public class UpdateMyThingForFooDomainService : IUpdateMyThingForBarDomainService
{
    public void UpdateMyThingForBar(BarCommand barHappened)
   {
      /*Other Stuff*/
   }
}

public interface IUpdateMyThingForFooDomainService
{
   void UpdateMyThingForBar(FooCommand barHappened);
}

public class UpdateMyThingForFooDomainService : IUpdateMyThingForFooDomainService
{
   public void UpdateMyThingForFoo(FooCommand barHappened)
  {
    /*Other Stuff*/
  }
}

Having split these individual classes out we might choose to avoid calling them directly, but instead decide to send a message to them. There are a number of reasons for this.

The first is that we decouple the caller from the service. This is useful where we might want to change what the service does – for example handle requests asynchronously, without modifying the caller.

The second is that we might want to handle orthogonal concerns orthogonally such as transactions or logging. Although we could use a technology like PostSharp to weave in aspects, a simpler approach is pipes and filters – create a pipeline with a series of steps, the end of which is our service. We then send a message, the framework instantiates a pipeline with those orthogonal concerns, the message is passed through the filter steps before arriving at the target handler.

In order to make this work the pipeline steps need to implement a common interface as this allows us to add Decorators that implement the same interface, forming a Chain of Responsibility.

 


public interface IHandleMessages
{
    void Handle(T command);
}

public class CreateMyThingHandler : IHandleMessages
{
    public void Handles(CreateMyThingCommand createMyThingCommand)
   {
      /*Stuff */
  }
}

public class UpdateMyThingForFooHandler : IHandleMessages
{
    [Logging]
    public void Handles(BarCommand barHappened)
    {
      /*Other Stuff*/
    }
}

public class Logger : IHandleMessages
{
    public void Handles(BarCommand barHappened)
   {
       /*Other Stuff*/
   }
}

The code is not shown here, but you may want to use attributes to document a handler and show the decorators in the chain of responsibility. You could use these to decide what decorators to put in the chain. However, It’s worth noting that real implementations that assemble a chain of responsibility often use an Inversion of Control container to resolve the handler and you will often find it easier to implement if you have an IDecorate interface. Some of the pipeline building code involves usually involves dealing with Type.MakeGenericType and you might want to be aware of that if you want to use this approach. I might do a separate post on building a chain of responsibility at a future date.

Note that this also serves to reduce the number of interfaces that we must implement as the generic interface can stand in for most of them.

Third is the number of dependencies our service has. We might have an action that we need to execute as part of the response to a number of actions by the user. We don’t want to repeat that code in every service. But, we also don’t want to have services calling too many other services, (that in turn may call other services), because we will get an explosion of dependencies for our service, and the service that it depends on. This makes it hard to get our service under test, or makes the tests unintelligible and results in anti-patterns like auto-mocking. The need for auto-mocking may be seen as a design smell: you have too many dependencies; resolution might be to use a command processor.

We gain some dependency advantages from the split into separate handlers, because each handler will have fewer dependencies than a service. But in addition we can separate concerns in our handlers, such that we focus on updating a small part of our domain model or object graph in each handler (in DDD terms we focus on an aggregate).

So to further limit the number of dependencies we prefer to publish a message (an event) from the service that handles the initial request, handing off any work that is related to handling the command, but applies to a different aggregate (and should potentially be in a different transaction and consistency boundary). This allows the framework to pass the message to those services, removing our dependency on them.


public class CreateMyThingHandler : IHandleMessages
{
    IProcessCommands _commandProcessor;
    IMyThingRepository _myThingRepository;

    public CreateMyThingHandler(IProcessCommands commandProcessor, 
         IMyThingRepository myThingRepository)
   {
      _commandProcessor = commandProcessor;
      _myThingRepository = myThingRepository;
   }

   public void Handles(CreateMyThingCommand createMyThingCommand)
  {
      /*Use Factory or Factory Method to create a my thing  */
      /*save my thing to a repository*/

      _commandProcessor.Publish(
          new MyThingCreated
              {/* properties that other consumers may care about*/}
          );
   }
}

In addition a command processor, because it is responsible for loading the services, is also the point at which an Inversion of Control (IOC) container is injected into our request handling pipeline, which removes any issues with lack of support for IOC containers in legacy platforms like WebForms.

Finally switching to a command processor eases our path to handling some requests asynchronously.

Disadvantages of using a command processor

One common criticism of using a command processor is that it adds a level of indirection. To read the code you have to identify how commands map to handlers. Naming conventions can help ease the burden, especially if used with tools like R#.

Posted in CQRS, DDD, Events, Object-Orientation, SOLID, Uncategorized | 14 Comments

Why Repository SaveUpdate is a smell

One of the idioms I see a fair amount of is the SaveUpdate method on a Repository. The intent is usually to persist an item to storage, using a SaveUpdate method to lazily avoid the question of whether it is a new object, or just one you are updating.

I have a couple of issues with this approach. The first is that a Repository is intended to have collection semantics and encapsulate the method used to obtain the data. Adding SaveUpdate makes it explicit that your repository is backed with some kind of persistent storage – why else would you need to save it. But a Repository does not encapsulate access to a Db, a repository is simply a collection of entities (in DDD aggregate roots) which is agnostic about where the entities are stored. A Repository might be entirely in memory, it might abstract a REST API on a separate service, then options are legion.

In most cases I would prefer that we have a similar interface to a collection: an Add method because I want to add new items into the collection, but not an update, because I should only need to change an object referenced from the collection for that.

Working with NHibernate (NH) this also works with NH’s paradigm rather than against it. This is my second issue: you should rarely need to ever call SaveUpdate in NH, and only rarely call Save.

NH distinguishes between two types of objects: transient and persistent. A persistent object is one that is in the Db, a transient one is in memory. When you Save against an NH session a transient object becomes a persistent one. When an object is loaded from the Db it is a persistent object. The key to this is the Identity Map pattern – NH has a list of all the objects loaded from the Db, so that it knows to serve them back up to you, if you ask for the object representing a row again during the session. The idea is that you want to use the version with any changes you have already made, not a fresh copy from the Db.

When NH flushes a session, or commits a transaction, it does a dirty check for all the persistent objects in your Identity Map, and saves any changes. That’s it, no need to call SaveUpdate, just flush the session or commit a transaction and your persistent objects will be saved. So Update is meaningless to call explicitly, NH will do it for you. (Understanding this is important, because auto-flush will commit dirty writes when your session terminates, even if you threw an exception; this may not be what you desired, in which case you should not autoflush but rely on explicit transactions).

This fits nicely with our Repository as collection metaphor: we don’t need to do anything with objects that already part of the collection post-updating them.

In addition NH supports persistence by cascade – you know those options you set on many-to-one, many–to-many relationships etc. Provided your cascade options require NH to follow a relationship, a persistent object will also save children in its object graph. Now this does not make any difference for already persistent objects, but transient ones that can be reached by following a cascade will be saved too.

This means that you do not need to call Save for an object that is added to the graph of an already persistent the dirty check will pick it up – so adding a new object in this case does not require a call to Save.

This makes sense for our Repository pattern, we don’t tend to call Add for the children in the object graph of entities we add to a collection, and there. It is also worth noting that this lends itself to the DDD idea of an Aggregate Root being what a Repository loads, we need to load root objects, not all their children. (Sadly NH does not really support the notion of a coarse-grained lock, which aggregates try to implement, but that’s a seperate issue).

This means that we only ever need to Save i.e. Add to our Repository, on new transient objects that have no association with existing objects (in DDD terms likely to be Aggregate Roots). There are usually a lot less of these than other kinds of entities. So once you challenge the idea of doing SaveUpdate, you naturally begin to move toward thinking about a Repository loading an object graph, and not an entity. By doing this you are both encapsulating your access to whatever backs the repository, and in the case of an Object-Relational Mapper (ORM) working with the ORM. A good ORM is intended to support the OO paradigm, if you don’t exploit its power to work seamlessly, but rely on old school explicitly CRUD operations on a Data Mapper then you miss some of the strengths of a well written ORM.

If you want to have explicit knowledge of the Db, and find it more comfortable to know that you are saving to the Db, use the Data Mapper pattern, not a Repository. Otherwise, consider that explicitly calling SaveUpdate (or synonyms of that) may well be a smell that you are pusing too much information about how persistence is done into your model.

Posted in .Net, DDD, NHibernate, ORM | 5 Comments

Mocks and Tell Don’t Ask

One of our alumni Karl blogged a request recently for folks to stop using mocks. Once upon a time I also made clear that I had a significant distrust of mocks. I’ve mellowed on that position over time, so I thought that I should explain why I have changed my opinion.

Perhaps it would be useful to give a summary of the discussion around this. Whilst I don’t think that you need to choose between being a classicist or mockist, I think that Martin Fowler’s article on Mocks Aren’t Stubs is still a good starting point for understanding the debate, because it talks about the different types of Test Double, as well as outlining approaches to their usage. However, for my part, Martin does not highlight Meszaros’s key distinction between replacing indirect inputs and monitoring indirect outputs. Both mention the danger of Over-specified Software from Mocks, and Meszaros cautions to Use the Front Door. On the other side the proponents of mocks have always pointed to their admonition to Mock Roles Not Objects {PDF}. Growing Object Oriented Software, Guided by Tests (GooS) is probably the best expression of their technique today.

The key to understanding mocks to me was that the motivation behind Mocks, revealed in GooS is to support the Tell Don’t Ask principle. Tim Mackinnon notes that:

In particular, I had noticed a tendency to add “getter” methods to our objects to facilitate testing. This felt wrong, since it could be seen as violating object-oriented principles, so I was interested in the thoughts of the other members. The conversation was quite lively—mainly centering on the tension between pragmatism in testing and pure object-oriented design.

For me understanding this goal for mock objects was something of a revelation in how I understood them to be used. Previously I had heard arguments that centered around the concept of a unit test needing isolation being the driver for use of mocking frameworks, but now I can see them as tools helping us avoid asking the object about its internal state.

Within any test we tend to follow the same pattern: set up the pre-conditions for the test, exercise the test and then check post-conditions. It’s the latter step that causes the pain for developers working towards a Tell Don’t Ask principle – how do I confirm the post-conditions without asking objects for their state.

This is a concern because objects should encapsulate state and expose behavior (whereas data structures have state but no behavior). This helps avoid feature envy, where an objects collaborator holds the behavior of that object, in a set of calls to discover its state instead of asking the object to carry out the behavior on the state itself. This leads to coupling and makes our software more rigid (difficult to change) and brittle (likely to break when we do change it).

But this leads to the question: how do we confirm the post-conditions if we have no getters?

Mocks come into play where we decide to confirm is the behavior of the class-under-test through its interaction with its collaborators, instead of through getters checking the state. This is the meaning of behavior-based testing over state-based testing, although you might want to think of it as message-based testing, because what you really care about is the messages that you send to your collaborators.

Now when we talk about confirming behavior, recognize that in a Tell Don’t Ask style the objects we are interested in confirming our interaction with are the indirect outputs of the class under test, not the indirect inputs (classes that we get state from). In an ideal world of course, we won’t have many indirect inputs (we want Tell Don’t Ask remember), but most people will tend to be realistic about how far they can take a Tell Don’t Ask approach. Those indirect inputs may continue to be fakes, stubs, or even instances of collaborators created with TestDataBuilders or ObjectMothers. Of course the presence of a lot of them in our test setup is a smell that we have not followed a Test Don’t Ask approach.

It is also likely that many of our concerns about over-specified software with mocks often come from the coupling caused by these indirect inputs over indirect outputs. They are likely to reveal most about the implementation of the their collaborator. By contrast where we tell an object to do something for us, we likely let it hide the implementation details from us. Of course we need to beware of feature envy from calling a lot of setters instead of simply calling a method on the collaborator. This chattiness is again a feature envy design smell.

I have come to see an over-specified test when using mocks is not a problem of using mocks themselves, but mocks surfacing the problem that the class-under-test is not telling collaborators to perform actions at a granular enough level, or is asking too many questions of collaborators.

Finally one question that often arises here is: if we are just handing off to other classes, how do we know that the state was eventually correct i.e. the algorithm calculated the right value, or we stored the correct information. One catch-all option is to use a visitor, and pass it in so that the class-under-test can populate it with the state that you need to observe. Other options include observers that listen for changes. Of course at some point you need to consume the data from the visitor or the event sent to the observer – but the trick here is to use a data structure where it is acceptable to expose state (but not to have behavior).

CQRS also has huge payoffs for a Tell Don’t Ask approach. Because your write side rarely needs to ‘get’ the state, you can defer the question of where we consume the data – the read side does it, in the simplest fashion of just creating data structures directly. Event Sourcing also has benefits here, because you can confirm the changes to the state made to the object by examining the events raised by the class under test instead of asking the object for its state.

Posted in .Net, Agile, BDD, Behavior Specification, Mocks, Object-Orientation, Stubs, TDD | 6 Comments