Home > Programming, Unit Testing > Some more TDD concepts

Some more TDD concepts

Please refer the following articles from where I’ve taken these tips –

Mocks Aren’t Stubs (by Martin Fowler)

State vs Interaction Based Testing (by Nat Pryce)

TDD Design Starter Kit – State vs. Interaction Testing (by Jeremy Miller)

The term Unit Testing implies that we are focusing on one element of the software at a time.

xUnit tests follow a typical four phase sequence: setup, exercise, verify, teardown.

The object (or class) which we want to test is called System Under Test (SUT) as per Gerard Meszaros xUnit patterns book. The other classes required along with the SUT are called collaborators.

The xUnit style of testing uses state verification: which means that we determine whether the exercised method worked correctly by examining the state of the SUT and its collaborators after the method was exercised.

The setup phase in testing with Mock objects is very different and is divided into two parts: data and expectations. Here, the SUT is the same, but the collaborator isn’t an object of the actual class, instead it’s a mock object. Once all the expectations are in place, the SUT is exercised.

Mocks use behavior verification, where we instead check to see if the SUT made the correct calls on the collaborator.

Meszaros uses the term Test Double as the generic term for any kind of pretend object used in place of a real object for testing purposes. He defined four kinds of double:

Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.

Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).

Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what’s programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it ‘sent’, or maybe only how many messages it ‘sent’.

Mocks are objects pre-programmed with expectations which form a specification of the calls they are expected to receive.

Of these kinds of doubles, only mocks insist upon behavior verification.

Classical and Mockist Testing

The classical TDD style is to use real objects if possible and a double if it’s awkward to use the real thing. So a classical TDDer would use a real warehouse and a double for the mail service. The kind of double doesn’t really matter that much.

A mockist TDD practitioner, however, will always use a mock for any object with interesting behavior. In this case for both the warehouse and the mail service.

An important offshoot of the mockist style is that of Behavior Driven Development (BDD).

Driving TDD

The mockists advocate a style called need-driven development. With this style you begin developing a story by writing your first test for the outside of your system, making some interface object your SUT. By thinking through the expectations upon the collaborators, you explore the interaction between the SUT and its neighbors – effectively designing the outbound interface of the SUT.

Once you have your first test running, the expectations on the mocks provide a specification for the next step and a starting point for the tests. You turn each expectation into a test on a collaborator and repeat the process working your way into the system one SUT at a time. This style is also referred to as outside-in, which is a very descriptive name for it. It works well with layered systems. You first start by programming the UI using mock layers underneath. Then you write tests for the lower layer, gradually stepping through the system one layer at a time. This is a very structured and controlled approach, one that many people believe is helpful to guide newcomers to OO and TDD.

One of the hardest things for people to understand in OO design is the “Tell Don’t Ask” principle, which encourages you to tell an object to do something rather than rip data out of an object to do it in client code. Mockists say that using mockist testing helps promote this and avoid the getter confetti that pervades too much of code these days. Classicists argue that there are plenty of other ways to do this.

Mockists favor role interfaces and assert that using this style of testing encourages more role interfaces, since each collaboration is mocked separately and is thus more likely to be turned into a role interface.

State vs Interaction based Testing

In an object-oriented design, an object’s state is an implementation detail that should be properly encapsulated and its interactions with its environment should be its only visible behaviour. If you follow the “Tell, Don’t Ask” style, objects have very little visible state to assert about.

When a program is divided into modules, likewise the internal state of a module is unimportant; it is only how a module interacts with other modules that matters. The behaviour of a program, and that of the objects within it, is defined solely in terms of message sending, and those messaging interactions are what should be tested.

The most important benefit of interaction based testing is that it helps reduce the amount of mutable state in a program. Mutable state makes a program harder to understand and maintain because the behaviour of a piece of code cannnot be easily predicted merely by reading the text but depends on the sequence of events that put it and its environment into signigicant states. By concentrating on the interactions between objects instead of state changes, interaction-based testing guides the design towards objects that transform data as they pass it around rather than store data and perform logic on the state of other objects.

State or Interaction Testing, Which Do I Want to Use?

Use whichever mode of testing is easiest to apply on a unit test by unit test basis. Both styles of testing need to be in your intellectual toolbox. State-based testing is generally easier because of the overhead associated with setting up the mock objects, but interaction-based testing is essential for dealing with external dependencies like databases or middleware and user interface testing.

Advertisements
Categories: Programming, Unit Testing
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: