Sunday 30 December 2012

Test Driven Development - objections, part 2

Welcome to part 2 of my post about TDD objections.

By the way, I found an interesting analysis on slideshare on the same topic. It's an interesting read, so be sure to take a look.

Where did we leave the last time?

Ok, let's take on the next set of objections from the list:

  1. Not enough time
  2. TDD will slow us down, because we'll have to create a lot of additional code
  3. TDD will slow us down, because we'll have to maintain a lot of additional code
  4. We don't have the necessary skills or experience
  5. We don't have the necessary tools
  6. (This one is unit testing specific) There are already other kinds of tests, we don't need unit tests?
  7. It's very hard to perform with legacy code
  8. I already know how to write a testable code, TDD will not really improve my design
  9. We've got enough quality and we're doing fine without TDD
  10. My manager won't let me do TDD
  11. There's no "scientific proof" and enough research on whether TDD really provides a return of investment

The ones I'm gonna talk about today are the one marked with strong text. Let's go then!

4. We don't have the necessary skills or experience

This is a valid impediment. However, its a common one in any skill. You see, it's an extremely rare situation that someone is proficient using a technique for the first time (think of the times when you learned how to use a keyboard and a mouse). Most techniques require some time and knowledge to master - the same is with TDD. Let's say that TDD is like a flower, where the core is the "Red-Green-Refactor" cycle and there are a lot of petals - good practices and heuristics. These include: need-driven design, triangulation, mocking, listening to tests etc.

Thankfully, lack of skills can be dealt with by providing training, mentoring, books, doing katas, randoris and by the teams drawing conclusions out of their own experience. In other words, this is a temporary obstacle. Of course, together with staff rotation in your team comes the need to renew part of the investment in skills, knowledge and experience.

5. We don't have the necessary tools

This too is a valid impediment. TDD is a kind of process that can be made a lot easier with tools. There are many areas where tools can improve the overall performance with TDD. These include:

  1. Code navigation
  2. Running unit tests
  3. Automated refactoring
  4. Code Analysis
  5. Quick fixes (like "generate method signature from its use)
  6. Continuous Testing
  7. Code generation

...etc.

If the issue is "money related" (e.g. there are tools on the market, but hey have to be bought), then the management should consider buying the best tools that are on the market and are available within the company budget. Thus, it's always good to have management buy-in for TDD. Thankfully, most of these tools (excluding the ones related to continuous testing) give a performance boost regardless of whether someone is using TDD or not, so many teams have such tools anyway.

If the issue is "technology related" (there are no tools on the market that work well with the technology your team is using), the good news is that TDD is usable even without these tools and still provides a lot of its benefits, since it is about analysis, design and specification. The tools only (well, "only" :-)) help in keeping focus and go faster through the whole cycle.

6. (This one is unit testing specific) There are already other kinds of tests, we don't need unit tests?

Although TDD is not solely limited to unit-level specs/tests, they form a crucial part of it. While some people believe that we can skip higher level specs in TDD, there's no one I know who says you can skip unit level.

Anyway, let's get to the point. this objection is based on a premise that TDD is about testing and "unit tests" produced with it are merely another kinds of tests. When I hear people raising this argument, they talk a lot about coverage, defect discovery, strengthening the testing net etc. Such arguments, for the most part, miss the point, since they ignore the biggest benefits of TDD which do not lie in its testing aspect (which I already discussed).

Dealing with such objections is really hard, because it requires others to accept a different point of view than the one they kept believing in so far. Sure, the books and authorities are on your side, but hey, the guys that read books and listen to authorities don't usually need convincing! So what to do in such case?

Remember, this argument is usually raised in teams that don't even do unit testing, let alone TDD. The following options are available:

  1. Point the opponents to the blog posts and literature - be careful with this. If you do it wrong, the other side may take it as questioning their professionalism. Also, they may just question the authorities you believe in - this is rather easy in software engineering world - they can just say "that doesn't convince me at all" and the game is over. You have to somehow show that you're passionate about TDD and point at such sources as to something that made you passionate. In other words, if you want to lead someone out of their biases, tell them that you too were led out before them and tell them how. This leaves them in a position of "look, there's a way to do things better" instead of "you're all idiots and only I know the truth". I'm hardly an expert on this matter, however, there are some "change patterns" that are worth checking out.
  2. Talk about your experiences from your previous projects if you have any or bring someone else if you don't. There are not many arguments as convincing as "I have experienced it myself", especially to the guys that don't have any experience in a certain field and are in a process of evaluating whether it makes sense to enter this field. Also, some people are more convinced by "soft" arguments ("we did it like this before and everybody in the team said that they feel in improvement in their coding style as never before"), while others are better convinced by "hard" arguments ("we did it like this before and we were able to get the best results of code complexity analysis in the whole project plus we were able to demonstrate a print out of documentation of 40 pages that just came out for free as we did TDD."). Also, better than words are living proofs ("you can just ask those guys I worked with and they show you what our living documentation looks like" or "Just ask the guys that were there with me on how they feel about it").
  3. Create an internal training. This has one big advantage and two small disadvantages. The advantage is that you have a lot of time (at least longer than on regular meetings) to lead people by hand through your argumentation, reasons, examples and so on. In other words, you're given a chance to give more full explanation of the idea. The first disadvantage is that usually you get to prepare for such training in your free time (since management usually approves only spending time on giving the training, not on preparing it). The second disadvantage is that the people that you want to convince can simply ignore the invitation to the training and not attend at all or (if they're forced to attend) they can spend the whole training doing their stuff on their laptops.

7. It's very hard to perform with legacy code

The version of this objection that I find valid is: "It's harder to perform with legacy code". Why? Because TDD requires the code to have a quality called "testability". Legacy code doesn't usually have it. Thus, the code has to be refactored, risking breaking something that already works (if you know how to do this, then the risk is significantly lower, but there's still some risk). On the other hand, there is this temptation to just "insert a little if clause right in the middle of this mess and be done with".

Anyway, the strategy to deal with this objection is to somehow make is clear that it's either "we don't have the necessary skills" or "we don't have the necessary tools" objection, just dressed differently. In the first case, take a look at the following books:

  1. Refactoring by Martin Fowler
  2. Dealing Effectively With Legacy Code by Michael Feathers
  3. Behead Your Legacy Beast. Refactor and Restructure Relentlessly With The Mikado Method (free e-book) by Daniel Brolund and Ola Ellnestam

and in the second case, talk to your boss and make sure that your team has the tools it needs.

Part 3 is already published! Go ahead and read it!

In the meantime, I'll be happy to hear your comments. I'm not an oracle and would gladly learn more about what objections do people receive and how they dispel them.

Thursday 27 December 2012

Test Driven Development - objections, part 1

Since you're reading this blog, you probably have your own, more or less informed, view on TDD. Maybe you already read a book or two, maybe you've got two (or twelve) years of TDD practice on your back, but maybe you've heard about TDD and about it being "cool" only recently and are merely striving to learn more? If that's the case you've probably got a lot of doubts on whether TDD is really beneficial or whether it will prove beneficial in the specific environment you happen to work in. You're eager to get started, but you wonder whether the time and effort spent on learning TDD will prove itself to be well spent.

During my adventure with TDD, I encountered many objections, either from myself (and they were dispelled by others) or from other engineers (these I tried to dispel myself). Today, I'd like to comment on some of those objections I met with when talking about TDD. In particular:

  1. Not enough time
  2. TDD will slow us down, because we'll have to create a lot of additional code
  3. TDD will slow us down, because we'll have to maintain a lot of additional code
  4. We don't have the necessary skills or experience
  5. We don't have the necessary tools
  6. (This one is unit testing specific) There are already other kinds of tests, we don't need unit tests?
  7. It's very hard to perform with legacy code
  8. I already know how to write a testable code, TDD will not really improve my design
  9. We've got enough quality and we're doing fine without TDD
  10. My manager won't let me do TDD
  11. There's no "scientific proof" and enough research on whether TDD really provides a return of investment

This post is around the first three points, marked with strong text. The later points will be discussed in part 2 of this post. Ok, let's go!

1. Not enough time

This is my favorite objection, just because dispelling it is so fun and easy. I usually approach this kind of objections with Gojko Adzic's argument on how to solve Not Enough Time. You see, "not enough time" is always a facade reason - it is there only to hide the true one. The only direct solution to "not enough time" is to "make more time", which, by the way, is impossible. Luckily, we can restate it into something solvable like "something prevents me from allocating time for TDD". The further actions depend on what is this "something". Maybe it's a boss that will punish their employees for not fulfilling the short term goals? Maybe it's lack of appropriate knowledge or training? Anyway, these issues can be dealt with. "Not enough time" can't.

2. TDD will slow us down, because we'll have to create a lot of additional code

This is actually a (partially) valid argument. TDD really does lead to creating more code, which costs time. However, this does not necessarily mean that the overall development process takes more time than not writing this additional code. This is because this "test code" is not being written just for the sake of "being written" :-). The act of writing and the code that is created as a result of this writing provide a great value to a single developer and an entire team.

TDD aids developers in the process of analysis. What would otherwise be a mental effort to make everything up inside your head, turns into concrete failing or impossible-to-write code. This generates questions that are usually better asked sooner than later. Thanks to this, there's no escape from facing uncertainty.

The case is different (at least for me) when developing without TDD. In this approach, I discovered that I tend to write what I know first, leaving what I don't know for later (in hope that maybe I'll learn something new along the way that will answer my questions and lower uncertainty). While the process of learning is surely valuable, the uncertainty must be embraced instead of being avoided. Getting away from answering some key questions and leaving them for later generates a lot of rework, usually at the end of iteration, where it's very dangerous.

When I do TDD and I encounter a behavior that I don't know how to specify, I go talk with stakeholders ("Hey, what should happen when someone creates a subscription for magazines already issued?"). Also, If someone asks me to clarify my question, I can show them the spec/test I'm trying to write for the behavior and say "look, this does not work" or "so the output should be what?". This way, I can get many issues if not solved, then at least on the table much sooner than in case of non-TDD coding. It helps me eliminate rework, save some time and make the whole process more predictable.

TDD also provides a big help when designing. It lets you do your design outside-in, beginning with the domain and its work-flows, not the reusable, versatile, framework-like, one-size-fits-all utility objects that end up having only 30% of its logic ever used. This way, TDD lets you avoid over-design (by the way, code reuse is a good thing, it's just that preliminary generalization is as dangerous as preliminary optimization).

On the other hand, by promoting a quality called "testability", it promotes loose coupling, high cohesion and small, focused, well encapsulated objects. I already did some posts on that, so I'm not gonna delve more into this topic here. Anyway, striving for high testability helps avoid under-design.

Another way to think about the process of doing TDD is that you're actually documenting your design, its assumptions, legal and illegal behaviors. Others will be able to read it and learn from it when they face the task of using your abstractions in a new context.

3. TDD will slow us down, because we'll have to maintain a lot of additional code

It's true that, when done wrong, TDD produces a mass of code that is hard to maintain. Refactoring becomes a pain, each added functionality breaks dozens of existing specs/tests and the teams seriously consider abandoning the practice.

This happens more often when the teams do not adopt TDD, but rather stick with unit tests and do it only for the sake of testing.

The truth is that TDD, when done right, helps avoid such situations. Also, this help is actually one of its goals! To achieve this, however, you need two things.

The first one is knowing TDD good practices that help you write only the specs/tests that you need, focus on behavior and discover interactions between different objects, limiting an impact of a change to a small number of specs/tests. I actually didn't write about it yet on my blog, but there are some other sources of information. Anyway, this issue is easily solvable by a combination of training, mentoring, books and experience.

the second thing is "listening to the tests", covered both by Steve Freeman & Nat Pryce (they call it Synaesthesia) and Amir Kolsky & Scott Bain (they call it Test Reflexology). The big idea is that difficulties in writing and maintaining specs/tests are a very much desired feedback on quality of your design (also make sure to look at James Grenning's post on TDD as a design rot radar).

In other words, as long as the design is good and you know how to write tests/specs, this whole objection is not a problem. Of course, there is still a code to maintain, but I found it to be an easy task.

Another thing to keep in mind is that by maintaining specs/tests, you're actually maintaining a living documentation on several levels (because TDD is not solely limited to unit level). Just think how much effort it takes to keep an NDoc/JDoc/Doxygen documentation up to date - and you never actually know whether such documentation speaks the truth after a year of maintenance. Things get better with tests/specs, which can be compared with the code just by running them, so the maintenance is easier.

Part 2 is already written! Read it!

Also, feel free to leave your comment. How do you deal with these objections when you encounter them? Do you have any patterns you can share?

Friday 14 December 2012

Reusing code in Test Data Builders in C#

This is a C# version of a post I did a while ago. Hope it's of any use.

Test Data Builders

Sometimes, when writing unit or acceptance tests, it's a good idea to use Test Data Builder. For example, let's take a network frame that has two fields - one for source, one for destination. A builder for such frame could look like this:

public class FrameBuilder
{
  private string _source;
  private string _destination;

  public FrameBuilder Source(string newSource)
  {
    _source = newSource;
    return this;
  }

  public FrameBuilder Destination(string newDestination)
  {
    _destination = newDestination;
    return this;
  }

  public Frame Build()
  {
    var frame = new Frame()
    {
      Source = _source,
      Destination = _destination,
    };
    return frame;
  }
}

and it can be used like this:

var frame = new FrameBuilder().Source("A").Destination("B").Build();

The issue with Test Data Builder method reuse

The pattern is fairly easy, but things get complicated when we have a whole family of frames, each sharing the same set of fields. If we wanted to write a separate builder for each frame, we'd end up duplicating a lot of code. So another idea is inheritance. However, taking the naive approach gets us into some trouble. Let's see it in action:

public abstract class FrameBuilder
{
  protected string _source;
  protected string _destination;
  
  public FrameBuilder Source(string newSource)
  {
    _source = newSource;
    return this;
  }
  
  public FrameBuilder Destination(string newDestination)
  {
    _destination = newDestination;
    return this;
  }
  
  public abstract Frame Build();
};

public class AuthorizationFrameBuilder : FrameBuilder
{
  private string _password;
  public AuthorizationFrameBuilder Password(string newPassword)
  {
    _password = newPassword;
    return this;
  }
  
  public override Frame Build()
  {
    var authorizationFrame = new AuthorizationFrame()
    {
      Source = _source,
      Destination = _destination,
      Password = _password,
    };
    return authorizationFrame;
  }
}

The difficulty with this approach is that all calls to FrameBuilder methods return a reference to FrameBuilder, not an AuthorizationFrameBuilder, so we cannot use calls from the latter after calls from the first. E.g. we cannot make a chain like this:

new AuthorizationFrameBuilder().Source("b").Password("a").Build();
  
This is because Source() method returns FrameBuilder, which doesn't include a method called Password() at all. Such chains cause compile errors.

Generics to the rescue!

Fortuntely, there's a solution for this. Generics! Yes, they can help us here, but in order to do this, we have to use a trick that in C++ world is called "Curiously Recurring Template Pattern" (don't know if it has any name in the C# world). By using the trick, we'll force the FrameBuilder (superclass) methods to return reference to its subclass (AuthorizationFrameBuilder) - this will allow us to mix methods from FrameBuilder and AuthorizationFrameBuilder in any order in a chain, because each method, not matter which of the classes it is defined in, returns a reference to a subclass.

Let's see how this works out in the following example:

//thankfully, the following is legal :-)
public class FrameBuilder<T> where T : FrameBuilder<T>
{
  protected string _source;
  protected string _destination;

  public T Source(string newSource)
  {
    _source = newSource;
    return this as T;
  }
  
  public T Destination(string newDestination)
  {
    _destination = newDestination;
    return this as T;
  }
}

public class AuthorizationFrameBuilder 
  : FrameBuilder<AuthorizationFrameBuilder>
{
  string _password;

  public AuthorizationFrameBuilder Password(string password)
  {
    _password = password;
    return this;
  }
  
  public AuthorizationFrame Build()
  {
    var frame = new AuthorizationFrame()
    {
      Source = _source,
      Destination = _destination,
      Password = _password,
    };
    return frame;
  }
}

Note that in FrameBuilder, the this pointer is cast to its generic type, which happens to be the sublass on which the methods are actually called. this cast is identical in every method of FrameBuilder, so it can be captured inside a separate method or property like this:

  T This 
  {
    get { return this as T; }
  }
    
  public T Source(string newSource)
  {
    _source = newSource;
    return This;
  }

Summary

This solution makes it easy to reuse any number of methods in any number of different builders, so it's a real treasure when we've got many data structures that happen to share some common fields.

That's all for today - Hope you enjoy the C#-specific version of the solution. By the way, in contrast to C++, C# allows one or two solutions other than chained methods to achieve the same data-building result. Can you name them?

Monday 26 November 2012

Explaining TDD to high school students

Some time ago, I took on a challenge to try and prepare a short introduction to TDD that would make a good presentation for high school students (let's say 45 minutes). As TDD is hard to grasp and get used to even by experienced programmers, I thought that this should be really basic, just to put the point across.

I've pretty much prepared the flow of the presentation. Today I'd like to publish a draft of the presentation in hope to get some constructive feedback and make it even better.

Oh, by the way, I put content associated with each slide below it. Have fun!

Here we go!

Let's start with something obvious. In every activity, it's good to have a goal. Whether you're a race car driver, or a painter or a golf player, or even a tourist laying on the beach to get some sun and rest, you tend to have a goal. Without a goal, it's hard to determine things such as: when am I finished? How do I know that I failed? What can cause me to break the activity? How often do I need to repeat the activity? There are some other questions that can be derived from "having a goal".

We, software engineers, also need to have goals when writing software.

Let's take an exemplary student that is thinking about writing an application "from scratch". His goal may be to create an application that looks and works like Thunderbird e-mail client.

And so, he sets on a journey to make his dream come true. However, the goal is a distant one and so reaching it may be very difficult. This is because there's nothing along the road to tell him whether he's actually closer to or further away from the goal. It's almost like embarking on a journey with eyes closed. In software engineering world, we talk about a project having a high risk associated to it.

However, there's an easy way out of this inconvenience.

If we can split the path into several shorter ones, by choosing a subset of functionality to deliver first, we can arrive at the goal faster and with lower risk. It's like stating "ok, first I need to get to the Statue Of Liberty, and from there...".

Using this approach, we can slowly, but reliably arrive...

...at the full goal. This ability is, of course influenced by another factor - whether or not we have the ability not to mistakenly go back to the point of start. In other words, if our journey is composed of three points: A, B and C, we want to be sure whether from B, we're going to C, not back to A. In order to do this, we need some kind of "landmarks". In software engineering terms, we talk about "a way to confirm existing functionality and avoid introducing regression".

Thus, it makes sense to draw two conclusions.

The first one is that wherever we go and whatever software we write, we cannot take it "in one bite" - we have to split the overall goals into shorter goals to get feedback earlier.

Also, we want to be sure whether we really reached the goal or is it just our imagination. We'd like to be be able to tell whether all the goals are achieved, and if not, we'd like to know what's the next goal we must fulfill in order to get the work done.

Also, we don't want to come back and re-add the functionality we already put in. When we reach one goal, we want to get right to the next one and so on until the application is finished. If we can't completely prevent breaking what already works when adding new functionality, we want to at least know instantly when it happens to address it right away when it's a little trouble to do so.

Thus, we need the goals to be easily and reliably verifiable, so that the first time we arrive at the goal, we want to be sure that we really did. Later, we'd also want to re-verify these goals easily to make sure we didn't lose them accidentally while trying to achieve further goals.

These were the conclusions upon which TDD is built. Now let's see how it looks like in practice, taking on a naive example.

Let's imagine that we're trying to write a function that will raise a number to a given power. Also, let's keep the problem at the primary school level, because that's approximately where I left my math skills :-).

Anyway, we know how the signature would look like - we take one number, and another one and raise the first to the power of another. Now we need to state some goals that will help us arrive at the target.

We can come up with few examples of how properly implemented power function should behave. Each of these examples describes a more general rule. Such examples are called "Key Examples". The first one tells us what about a special case when we take anything and raise it to the power of 0. The second one describes a special case when we take anything and raise it to the power of 1. The third one illustrates the general rule that when we raise something to the power of N, we multiply it N times.

A set of key examples together with more general description forms a specification. Long gone are the times when the best way to write specification was to develop an abstract model of it. Nowadays, we want each rule implemented by the system to be illustrated by a concrete example. That's because...

...it's very easy to translate the speification made up this way into code, making it executable. This way, we're achieving the so-desired verifiability - if the specification is written as code that actually invokes the developed logic, we can reliably verify whether we really achieved the specified goals. Also, we can re-verify it later in no time, since code executes blazingly fast compared to a human that would need to read the specification and compare it with the actual code.

Ok, so let's take on the first statement of this specification and try to put it in the context.

In order to write and run specifications, we use special tools that provide some infrastructure upon which we can build. Such tools will automate many tasks for us, so we just need to write what we want and the tool will take care of gathering the specifications, executing them and reporting the result. For this example, we're gonna use a framework that's called XUnit.Net.

XUnit.Net allows us to state "facts" about the developed systems, by creating methods and marking them with [Fact] attribute and stating what is the expected behavior of the developed system. If the result is in sync with what we expect, the tool will mark such example as "passed" (usually using green color). If the result is not in sync, the tool will make the example as "failed" (usually using red color). Also, the specification needs a name. We try to name it after a description of the general rule illustrated by the example, so that we can easily come back to it later and read it as a "living documentation".

Now that we have prepared the necessary infrastructure, let's try adding some content to the example.

First, we state our assumptions. We often think about examples in executable specifications in terms of three sections: "Given" (assumptions), "When" (action), "Then" (desired result). We treat it as a general template for a behavior description. In this case, our assumption is that we have any number which happens to be 3 (but the name points that it can be any other number as well). We understand the code we just wrote as "given any number".

Now for the action, or "When". In our case, the action that we want to describe is taking something to the power of 0. Note that we use 0 explicitly and not give it any name. This is to stress that the described behavior takes place only when we use 0 here. This part should be understood as "When we raise it to the power of 0".

And now, the desired result, or "Then". Here, we state what should happen when the behavior is in place - in other words, what will make the example "passed" (green). In our case, we say "Then the result should be equal to 1". If this is not true, the example will be marked as "failed" (red).

Ok, let's quickly recap by trying to read the whole example. It reads like this:

Given any number
When I raise it to the power of 0
Then the result should be equal to 1

Our goal is to make this example "pass" (green) - when we it happens, the tool will display a message like the one on the slide. Note that the goal fulfills the criteria that we defined earlier. It is:

  • short
  • incremental - covers a well defined part of the functionality
  • verifiable - we can compile it, run it and in a second, we'll get a response on whether this goal is achieved or not.

By the way, this goal is so far unfulfilled. We don't have any code to even get past the compilation stage...

So let's add some. Note that we're deliberately putting in an implementation that will make this example "failed" (displayed in red). This is to make sure that the goal is well-stated. One can, by mistake, make an example that will always "pass", and we want ourselves protected from this kind of errors. Thus, we make the first implementation as naive as possible just to compile it and watch it not fulfilling our current specification.

The example we have created seems state the goal well. As the system does not work the way this example describes, it shows "failure" (in red), meaning that the goal is not achieved yet. Our task is to achieve it.

Thankfully, this simple goal could be achieved by changing one character in the original implementation. This is just enough implementation to put the desired behavior in place. Done.

"Wait a minute" - you may say - "this isn't a proper implementation of power algorithm! It's cheating!". And you may give some examples where the current implementation won't work...

...like 2 to the power of 2. If you really said this, all of this would actually be correct, except for the "cheating" part :-).

That's because TDD process consists of small cycles, where we do provide the simplest implementation possible and expand it when we expand the specification with new examples.

This process is usually called "Red - Green - Refactor" and consists of three stages:

  1. Red - named after the color that the tool for running executable specification shows you when the goal stated with an example is not achieved. We saw this when we made out Pow() method return 0 instead of expected 1.
  2. Green - named after the color that the tool shows you when the goal stated with example is achieved by the current implementation. We saw this when we put in the correct implementation for "anything to the power of 0" scenario.
  3. Refactor - After achieving the goal and making sure no previous goals were lost, it's a good moment to take a step back and look at the current design. Maybe the behaviors added on "one by one" basis can be generalized? Maybe something other can be cleaned up? In our case, no refactoring was needed, since there was hardly any design, however, in real-life scenarios, this is a crucial step.

When we finish the whole cycle, we take on another goal and do over until we run out of goals. That's the core of the TDD process.

Now's the time for a confession - you thought this presentation was about Test-Driven Development, but until now, I didn't even mention the word "test" - I was only talking about goals, specifications and examples. So where are the tests?

Ok, here's the thing: we use the examples to state our goals and verify their achievement up to the moment when the logic is in place. After this happens, we don't throw out these examples - they take on the role of micro-level tests that ensure all behaviors persist when we add more logic. These "tests" are a by-product of the TDD process.

The example we went through just now was a simplified case of a single function. As you surely know, the real-world projects, especially those object oriented ones, are not like this. They consist of a web of objects, collaborating together to achieve a task.

Most of these objects know about other objects and use them. In other words, object depend on other objects. Some say that object orientation is all about managing dependencies. How does TDD fit here?

Using examples, we can specify how an object should interact with its collaborators, even those that do not exist yet. "What?" - you may ask - "how am I supposed to create an example of an object that uses something which does not exist?". True, it's impossible per se, but there are ways to deal with that.

The trick is to develop fake objects that look like the real ones on the surface, but underneath, they allow us to set up their behavior, so that the specified object "thinks" different things happen in the system. It's like taking over all media in real life and broadcasting fake auditions about earthquake in New York - people in other countries, who know about current situation in New York from media only will believe the lies and act like they were real. Here, we wanna do the same thing - cheat an object about what happens in its surrounding to write examples on how it should behave.

In order to do it, we can use polymorphism. Let's take a look at two examples of such fake objects.

Sometimes, we want to state that the specified object should communicate something to its collaborators. Let's say we have a drive full of music and we want to show an example where our object makes an attempt to play the music. If we used the real drive, the music playing or not could result from many different conditions (like file privileges, format, whether there are actually any files on the drive etc.) which are out of scope of this example. To make things easier, we use a fake object, cheating our specified one into thinking that it's dealing with a real drive.

This is the second type, that allows us to set up a value returned by a method. Using this object, we can cheat the users of the drive into thinking that it's read only. If we used a real drive, we would probably have to invoke some complex logic to set it in this state. With a fake, we can just pre-program an answer that will be issued when the question gets asked.

The End

That's all I have for now, I'd be grateful for any feedback on this draft. Bye!

Tuesday 20 November 2012

Reusing code in Test Data Builders in C++

Test Data Builders

Sometimes, when writing unit or acceptance tests, it's a good idea to use Test Data Builder. For example, let's take a network frame that has two fields - one for source, one for destination. A builder for such frame could look like this:

class FrameBuilder
{
protected:
  std::string _source;
  std::string _destination;
public:
  FrameBuilder& source(const std::string& newSource)
  {
    _source = newSource;
    return *this;
  }

  FrameBuilder& destination(const std::string& newDestination)
  {
    _destination = newDestination;
    return *this;
  }

  Frame build()
  {
    Frame frame;
    frame.source = _source;
    frame.destination = _destination;
    return frame;
  }
};

and it can be used like this:

auto frame = FrameBuilder().source("A").destination("B").build();

The issue with Test Data Builder method reuse

The pattern is fairly easy, but things get complicated when we have a whole family of frames, each sharing the same set of fields. If we wanted to write a separate builder for each frame, we'd end up duplicating a lot of code. So another idea is inheritance. However, taking the naive approach gets us into some trouble. Let's see it in action:

class FrameBuilder
{
protected:
  std::string _source;
  std::string _destination;
public:
  FrameBuilder& source(const std::string& newSource)
  {
    _source = newSource;
    return *this;
  }

  FrameBuilder& destination(const std::string& newDestination)
  {
    _destination = newDestination;
    return *this;
  }

  virtual Frame* build() = 0;
};

class AuthorizationFrameBuilder : public FrameBuilder
{
private:
  std::string _password;
public:
  AuthorizationFrameBuilder& password(const std::string& newPassword)
  {
    _password = newPassword;
    return *this;
  }

  Frame* build()
  {
    auto authorizationFrame = new AuthorizationFrame();
    authorizationFrame->source = _source;
    authorizationFrame->destination = _destination;
    authorizationFrame->password = _password;
    return authorizationFrame;
  }
}

Note that there are two difficulties with this approach:

  1. We need the build() method to return a pointer, or we'll never be able to use methods from FrameBuilder in the chain (because each of the methods from FrameBuilder returns a reference to FrameBuilder, which only knows how to create frames, not how to create authorization frames). So, we'll need the polymorphism to be able to perform chains like:
    AuthorizationFrameBuilder().password("a").source("b").build()
  2. Because FrameBuilder calls return a reference to FrameBuilder, not an AuthorizationFrameBuilder, we cannot use calls from the latter after calls from the first. E.g. we cannot make a chain like this:
    AuthorizationFrameBuilder().source("b").password("a").build()
    This is because source() method returns FrameBuilder, that doesn't include a method called password() at all. Such chains end up in compile errors.

Templates to the rescue!

Fortuntely, there's a solution for this. Templates! Yes, they can help us here, but in order to do this, we have to use the Curiously Recurring Template Pattern. This way we'll force the FrameBuilder methods to return reference to its subclass - this will allow us to mix methods from FrameBuilder and AuthorizationFrameBuilder in any order in a chain.

Here's an example code for the solution:

template<typename T> class FrameBuilder
{
protected:
  std::string _source;
  std::string _destination;
public:
  T& source(const std::string& newSource)
  {
    _source = newSource;
    return *(reinterpret_cast<T*>(this));
  }

  T& destination(const std::string& newDestination)
  {
    _destination = newDestination;
    return *(reinterpret_cast<T*>(this));
  }
};

class AuthorizationFrameBuilder 
: public FrameBuilder<AuthorizationFrameBuilder>
{
private:
  std::string _password;
public:
  AuthorizationFrameBuilder& password(const std::string& password)
  {
    _password = password;
    return *this;
  }

  AuthorizationFrame build()
  {
    AuthorizationFrame frame;
    frame.source = _source;
    frame.destination = _destination;
    frame.password = _password;
    return frame;
  }
};

Note that in FrameBuilder, the this pointer is cast to its template type, which happens to be the sublass on which the methods are actually called. this cast is identical in every method of FrameBuilder, so it can be turned into a separate method like this:

  T& thisInstance()
  {
    return *(reinterpret_cast<T*>(this));
  }

  T& source(const std::string& newSource)
  {
    _source = newSource;
    return thisInstance();
  }

Summary

This solution makes it easy to reuse any number of methods in any number of different builders, so it's a real treasure when we've got many data structures that happen to share some common fields.

That's all for today - if you'd like to, please use the comments section to share your solution to this problem for other programming languages.

Bye!

Tuesday 13 November 2012

Don't use setup and teardown, or I will...

...write a blog post.

There - I did it. I told you I would!

This time, I'm going to share some of my reasons why I tend not to use Setup and Teardown mechanism at all.

First, a disclaimer - my point here is NOT that Setup and Teardown lead to inevitable catastrophe. My point here is that Setup and Teardown are so misunderstood and so easy to abuse, that I'd rather not use them at all. There are some other reasons why I actually prefer not having Setups and Teardowns even when they are used properly, but I'll save this for another post. This time, I'd like to focus only on the ways this mechanism is most often abused.

What's Setup and Teardown?

As everyone knows, a Setup method is a special kind of method that is executed by unit testing tools before each unit test in the suite. Such methods are commonly used to set the stage before a unit test begins. Analogously, "Teardown" method is a method that is always run after unit test execution and is usually used to perform cleanup after the test finishes. So, given this code (example uses NUnit):

[Setup]
public void Setup()
{
  Console.WriteLine("SETUP");
}

[Teardown]
public void Setup()
{
  Console.WriteLine("TEARDOWN");
}

[Test]
public void Test2()
{
  Console.WriteLine("TEST");
}

[Test]
public void Test1()
{
  Console.WriteLine("TEST");
}

... when it is run by a unit testing tool, it produces the following output:

SETUP
TEST
TEARDOWN
SETUP
TEST
TEARDOWN

While having the common logic for "setting the stage" and "cleaning up" in test suite looks like adhering to DRY, avoiding duplication etc., there are, however, certain dangers when using this kind of mechanism, some of which I'd like to list below.

Issues with Setup and Teardown

Because we're talking mostly about C#, we're mainly going to examine Setup, because Teardown is seldom used for unit tests in such languages. By the way, the examples provided are to explain what kind of abuse I have in mind. I tried to keep them simple - this way they're more understandable, but do not show how bad can it get with real code and real project - you'll have to believe :-). Let's go!

Joint Fixtures

Imagine that someone has a set of unit tests evolving around the same setup (let's call it "A"):

[Setup]
public void SetUp()
{
  emptyList = new List<int>(); //A
}

[Test] //A
public void ShouldHaveElementCountOf0AfterBeingCreated() 
{
 Assert.AreEqual(0, emptyList.Count());
}

[Test] //A
public void ShouldBeEmptyAfterBeingCreated()
{
  Assert.True(emptyList.IsEmpty());
}

One day, another set of unit tests must be added for the same class that requires the setup to be handled a little bit differently (let's call it "B"). What this person might do is to just add the necessary setup besides the first one.

[Setup]
public void SetUp()
{
  emptyList = new List<int>(); //A
  listWithElement = new List<int>() { anyNumber }; //B
}

[Test] //A
public void ShouldHaveElementCountOf0AfterBeingCreated() 
{
 Assert.AreEqual(0, emptyList.Count());
}

[Test] //A
public void ShouldBeEmptyAfterBeingCreated()
{
  Assert.True(emptyList.IsEmpty());
}

[Test] //B
public void ShouldNotContainElementRemovedFromIt()
{
  listWithElement.Remove(anyNumber);
  Assert.False(listWithElement.Contains(anyNumber));
}

[Test] //B
public void ShouldIncrementElementCountEachTimeTheSameElementIsAdded()
{
  var previousCount = listWithElement.Count();
  listWithElement.Add(anyNumber);
  Assert.AreEqual(previousCount + 1, listWithElement.Count());
}

The downside is that another person striving to understand one unit test will have to read both through the related setup and the unrelated one. And in real life scenarios such orthogonal setups tend to be longer that in this toy example.

Of course, this may be fixed by separating this class into two - each having its own setup. There are, however, two issues with this: one is that this is almost never done by novices, and the second is that it usually complicates navigation through the unit tests.

Locally Corrected Fixtures

Another temptation a novice may face is when one day they need an object that's slightly different than the one already set up in the Setup. The temptation is to, instead of create new object configured separately, undo some of the changes made by the Setup just for this single test. Let's see a simplified example of a situation where one needs a radio set up slightly differently each time:

[Setup]
public void Setup()
{
  radio = new HandRadio();
  radio.SetFrequency(100);
  radio.TurnOn();
  radio.SetToSecureModeTo(true);
}

[Test]
public void ShouldDecryptReceivedContentWhenInSecureMode()
{
  var decryptedContent = radio.Receive(encryptedContent);
  Assert.AreEqual("I love my wife", decryptedContent);
}

[Test]
public void ShouldThrowExceptionWhenTryingToSendWhileItIsNotTurnedOn()
{
  radio.TurnOff(); //undo turning on!!

  Assert.Throws<Exception>(() =>
    radio.Send(Any.String())
  );
}

[Test]
public void ShouldTransferDataLiterallyWhenReceivingInNonSecureMode()
{
  radio.SetSecureModeTo(false); //undo secure mode setting!!

  var inputSignal = Any.String();
  var receivedSignal = radio.Receive(inputSignal);

  Assert.AreEqual(inputSignal, receivedSignal);
}

Overloaded fixtures

Let's stick with the hand radio example from previous section. Consider the following unit test:

[Test]
public void ShouldAllowGettingFrequencyThatWasSet()
{
  radio.SetFrequency(220);
  Assert.AreEqual(220, radio.GetFrequency());
}

Ok, looks good - we specify that we should be able to read the frequency that we set on the radio, but... note that the radio is turned on in the Setup, so this is actually getting a frequency from a radio that's turned on. What about if it's turned off? Does it work the same? In the real world, some radios are analog and they allow manual regulation of frequency with a knob. On the other hand, some radios are digital - you can set their parameters only after you turn them on and they become active. Which case is it this time? We don't know.

Ok, I actually lied a little. In fact, if someone was doing TDD, we can assume that if the scenario was different when a radio is off, another unit test would exist to document that. But in order to determine that, we have to: 1) look through all the unit tests written for this class, and 2) really, really believe that the author(s) developed all the features test-first. An alternative is to look at code coverage or at the code itself. However, all these ways of dealing with the issue require some examination that we have to perform. In such case, the Setup gets in the way of understanding a minimum activities required for a functionality to work as described.

Scope hiding

It's quite common to see unit tests grow too big in scope as the design gets worse and worse and it's harder and harder to separate different bits and pieces for unit testing. Many people think that Setup and Teardown are THE feature to deal with this. I'm sorry, they are not. If you have issues with your design, the right way to go is to SOLVE them, not to HIDE them. Unfortunately, this kind of Setup abuse tends to grow into multi-level inherited Setups (do class names like "TestBase" ring a bell?), where no one really knows anymore what's going on.

Evading already used values

Consider the following example of a user registration process that may take place in various situations (e.g. creating sessions, presidential election etc.):

[Setup]
public void Setup()
{
  registration = new UserRegistration();
  registration.PerformFor("user1");
  registration.PerformFor("user2");
}

[Test]
public void ShouldBeActiveForRegisteredUsers()
{
  Assert.True(registration.IsActiveFor("user1"));
}

[Test]
public void ShouldBeInactiveForUnregisteredUsers()
{
  //cannot be "user1" or "user2" or it fails!
  Assert.False(registration.IsActiveFor("unregisteredUser"));
}

Why "unregisteredUser" was chosen as a value for unregistered user? That's because someone writing a unit test wanted to evade the values used in Setup. While that's not as bad when reading those unit tests, it's a pain when writing new ones - in order to avoid conflict, you have to always look back at what users are already registered and either use the same values or deliberately pick different ones. Thus, writing every new test begins with trying to understand what the Setup already does and trying to get around that. What's worse, when putting another value in the Setup, we have to go through all existing unit tests to make sure that we pick a value different that already used in any of them. This hurts maintainability.

Why do I tell teams to avoid Setup and Teardown

As Roy Osherove once told me:

I don't use my frameworks to teach me design.

and while it was in a different context, I can paraphrase it into saying that avoiding using a feature instead of learning how not to misuse it is not something that will teach you good design and TDD.

Why then do I insist that people new to unit testing hold back from using features such as Setup and Teardown? How is it helpful?

In my opinion, holding back from using Setup and Teardown exposes us to a diagnostic pain - when we feel the pain and we cannot work around it, we have to learn to avoid it. It's never sufficient to say "don't use Setup and Teardown" or put in any other rule (e.g. "no getters") without following up on experience from applying this rule. When the team gets into difficulties, there has to be someone to explain what's the root cause. Only then do such rules make sense. If not for this, the team would just find another workaround, e.g. with helper methods (which are better than Setup and Teardown in that you always get to choose every time which ones to use and which not, but can also be abused). Thus, when I say "no Setup/Teardown" to a team, I always wait for a reaction like "you're nuts!" - through such experiences, I'm preparing them to acknowledge that TDD is something different that they initially thought (which is usually something like "execute a lot of production code" and "get a high coverage").

How about experienced developers? Do they need to adhere to the same rule? Well, let me share my experience. I told myself once - if I ever run into a situation where it makes perfect sense to use Setup and Teardown, I will not hold myself back. Guess what - since then, I used it only once (because one technique of dependency injection required it) and I was regretting it later. Other than this, I never really felt the need to use this feature, since I was doing even better without it. There are some other advantages (like keeping each unit test a "one part story") that make me never want to go back. Where I work, we've got over a thousand of unit tests and no Setup and Teardown at all.

There are actually more smells and difficulties associated with Setup and Teardown (like impeding certain refactorings) and I could also write something more about Setup and Teardown vs helper methods, but everything has to have an end, doesn't it? Till the next time!

Saturday 27 October 2012

Starting off with unit testing and TDD? Here's my advice...

Thanks to Mark Mishaev for inspiration.

Sometimes, I hear that someone is trying to start off with unit testing or TDD and they ask me for some good advice on where to start - some general guidelines that would help them along the way. I thought I'd summarize my usual answer here for everyone to benefit from.

So, if you're starting off with unit testing or TDD, here's my advice:

  1. Read at least these blogs to grasp some good practices:
  2. Pick up some books on the subject. The topic of unit testing and TDD might seem straightforward (there are a lot of simplifications around, such as "unit test is just a small code that creates a class, invokes a method and performs assertions on its output" and "TDD means you write your test first, then write the code"), but it actually requires quite a bit of knowledge to get things right. Also, don't limit yourself to a single book - read at least three or four - many TDD gurus have more or less different styles of doing TDD and writing unit tests and your own technique will get more and more flexible as you manage to understand more of them.
  3. Try writing your tests first. For a list of benefits, take a look at:
    1. The importance of test failure
    2. Test First - why is it so important?
  4. For new code, try to follow Need Driven Development
  5. To drive your code and design, try exposing yourself to “diagnostic pain”. This means putting some limitations onto yourself and when you’re tempted to break them, it means that the code or design is at fault and you should refactor. To give you a quick example, I do not use Setup and TearDown kinds of methods in unit tests (not mentioning Action Attributes from NUnit), which means all the objects used in the unit test are created in the body of the test method itself. I sometimes use helper methods when they improve readability and understandability of the test (but not to hide redundancy - that's the catch). At first it might look awkward, but I have created a lot of unit tests without Setup and Teardown and I'm very happy with the result. So it’s not like I don’t know how to use a unit testing framework - I deliberately hold back from using many of its features
  6. Ideally, a maintainable unit test has to fulfill three conditions, as pointed by Scott Bain:
    1. It fails reliably when behavior specified by it is broken
    2. It fails only when behavior specified by it is broken (so breaking another behavior should not break this test)
    3. No other unit tests will fail when behavior described by this test is broken
    This is the ideal - try to keep as close to it as possible.
  7. Try using a technique called Constrained Non-Determinism. You can either use tools that help with this (like AutoFixture for C#) directly, or you can wrap it in your own class (if you're reading my blog, you probably know that I like to wrap creating anonymous values in a class called Any). Alternatively, just roll out your own mini library or a set of functions.
  8. Use continuous testing tools, (examples for .NET include Mighty Moose (free) or NCrunch (paid)) for running your unit tests. If no such solution exists for your programming language of choice, you can always write a script that performs continuous compilation and running unit tests and lets you know of the results. There are some tools like Watchr that can make writing such scripts easier (especially when integrated with your operating system's default user notification mechanism).
  9. Always specify class behaviors (not methods or classes) with unit tests – to help you with this, try using the following convention of naming your tests: ShouldXYZ() where XYZ is the description of the behavior the class should supply. The convention is taken from Dan North’s post and helps to avoid:
    1. Check-it-all unit tests – where one does a single setup and verifies multiple behaviors.
    2. Names that do not make sense. I saw one a unit test named: SendFrameMethodSendsFrame() which tells almost nothing about the behavior. The “Should” naming forces us to rethink the name and come up with something like: ShouldPassReceivedValidFrameThroughTheMessageQueue() which works better.
    3. Also, pick names that read well when converted from "ThisNamingConvention" (or "This_naming_convention" - whatever you choose to apply to your unit test methods) to "this naming convention" – it lets you use the unit test results report in Cruise Control or Jenkins as a living documentation of your code after you apply a little post-procesing to it.
    4. You can look at my blog post that discusses the repercussions of bad naming.
  10. When choosing a mocking framework for your project, put your money on ease of use and readability. For example, many mocking frameworks for C# use lambda expressions everywhere, but many programmers are still not used to thinking in terms of expressions and are a bit confused. When developers find using such framework awkward, they're more likely to reject the idea of unit testing or TDD. Thus, as a main mocking framework, I like to choose NSubstitute.
  11. Always keep handy a "fallback mock framework" - there are some features that your main mocking framework of choice does not support or that are difficult to achieve using this framework. For example, NSubstitute does not yet support partial mocks. That's why it's good to have a secondary mock framework of choice that can make up for the main one's weaknesses in some rare cases. For such a fallback mock framework, I like to use Moq, but that may as well be FakeItEasy or Rhino Mocks or something else - depending on what you need.
  12. Try to stay as close as possible to SOLID principles and adhere to the Law Of Demeter (which is a conclusion from those principles, specifically - from Open Closed principle) – all of this lets you write better, more focused and more maintainable unit tests. For a list of smells that show the problem is in the design rather than in tests, see:
    1. Test Reflexology - part 1
    2. Test Reflexology part 2
    3. TDD and Single Responsibility Principle
    4. Mocking method chains, part 1: when not to
    5. A kata challenge to try your TDD skills on - failure and what we can learn from it
  13. Watch out for unit tests execution times – unit tests that run for more than 2-3 seconds (to tell you the truth, many should even run in less than one second), almost always have a smell attached to them – either they touch external resources or are not unit tests. Staying away from external resources may be tricky. For one such example where this actually does get tricky and one may be tempted to break the isolation, see my example related to timers
  14. Avoid the "The code is so straightforward that there’s no need to test it" thinking. When the code is complex, the solution is refactoring, not unit-testing (of course, tests can be written, but they have to be used as coverings). Unit tests are about specification, not coverage, and short specifications are good.
  15. Perform a kata or two on your own. One such kata and its exemplary solution are posted on this blog
  16. There may be a temptation to write more coarse-grained tests/specifications that are tied to the code (they’re sometimes called white-box tests). This is possible, however, I recommend not to do it if it’s not very well thought. I’ve been in projects where coarse-grained, so called “white-box tests” led to situations where correcting and debugging the tests took twice as long as changing the code. Again, it’s possible to write good coarse-grained tests, it just that it’s hard – it requires reading some books and doing few dry runs to grasp many best practices that are different than in case of unit tests. On short discussion of how things may go wrong, be sure to look at my post: Perfect from the start.
  17. Also, there may be a temptation to "test private methods". This is a sign that things are going a little bit offroad.
  18. Attaining X% code coverage should not be a goal. High coverage is good when it’s a side effect.

I could go on writing, but I think these are the most important, non-obvious things I learned throughout my adventure with TDD. As always, feel free to add your advice in the comments.

See ya!

Monday 22 October 2012

TDD tutorial: Validation Kata - a better implementation

Hi, last time, I tried to show you how to screw up the kata I published some time ago. This time, I'll try to examine the right (or "more right" :-)) way of doing it, using what the specifications told us the last time. The post turned out so long that I thought about splitting it, but hey, we're living in a "Push To Kindle" age, so here it is - the full thing as a single document. Enjoy!

I'll start again from scratch, thus I'll have to repeat some of the stuff from previous post to spare you the effort made on jumping back and forward between this post and the previous one. Don't worry, even the steps that are going to be the same as previously, are written differently, since I was not copy-pasting anything but wrote everything again.

This time, I'll divide each TDD cycle into four stages:

  1. Create a specification - we create a specification in a Given-When-Then form and translate it into code. At this point, it will probably not compile, often it won't be complete (e.g. will be missing some variable declarations)
  2. Make it fail for proper reason - at this point, we make our specification compile by supplying all the necessary types, variables etc. Also, just failing is not enough for us - we want the spec to fail either on assertion or mock verification. In other words - the spec must be failing because the expected end result is not supplied by the production code
  3. Make it pass - at this point, we implement the behavior (of course, the simplest thing that will make the current spec pass and not break any other spec)
  4. Examine TODO list - when finished, we need to determine our next step. Since TDD is broken down into short cycles, each of them having its own goal, we have to constantly evaluate our list of goals - the TODO list, adding items, removing items and choosing next item to implement.

For educational purposes, I'll not be doing refactoring - a short explanation why is at the end of this post.

Let's begin!

First, we'll need to start with something. Thus, we'll add the following two items to the TODO list:

  1. Create entry point to the module (top-level abstraction)
  2. Describe main work-flow of the module

By the way, new items on TODO list will always be in bold.

Let's take on the first item, since it's a prerequisite for everything else.

Specification 1: Creating new instances of MessageProcessing class

What we need first is our top-level abstraction. Since our task is to create a message processing module, I'll name the top-level abstraction: MessageProcessing.

By the way, I could name it MessageProcessor, but personally, I don't like such names. In my opinion, names of classes and interfaces should represent domain concepts and our domain does not tell anything about processor, validator, etc, but processing and validation, so these are the names I'm gonna use.

Create a specification

We have to create a need for this class to exist, and we can do this by making the following creational specification:

Given nothing
When I create a new instance of MessageProcessing class
Then it should not result in any kind of exception

Which, translated into code, looks like this:

[Fact]
public void ShouldAllowCreatingNewInstances()
{
  //GIVEN

  //WHEN
  Action whenCreatingANewInstanceOfMessageProcessingClass
    = () => new MessageProcessing();
  
  //THEN
  Assert.DoesNotThrow(whenCreatingANewInstanceOfMessageProcessingClass);
}

With this spec, we created a need to have a public MessageProcessing class with a parameterless constructor. Not much, but not bad either for so few lines of code.

Note that in this spec, I created a named action variable and then passed it into the Assert.DoesNotThrow() method. This is not how it's usually used - most of the time, the lambda is passed inline into the method. I did it differently to make the Given-When-Then structure of this spec explicit.

Make it fail for proper reason

First, we have to make it compile. This can be achieved simply by creating a MessageProcessing class. Also, to make sure it can fail, we create a parameterless constructor with an exception inside:

public class MessageProcessing
{
  public MessageProcessing()
  {
    throw new Exception();
  }
}

Creating this constructor is not necessary in such simple case (without it, the spec would already pass), but I do it here anyway just to show you that we can almost mechanically transition between the four stages explained at the beginning of this article.

Now the spec fails for the correct reason - we expect the constructor not to throw, but it does.

Make it pass

In order to make this spec pass, we just remove the parameterless constructor. It was there only to ensure us that the spec can fail for the proper reason and now there's no need for it. And here's the code:

public class MessageProcessing
{
}

Examine TODO list

After creating our top-level abstraction, our TODO list looks like this:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main work-flow of the module

We have one item left on the TODO list - implement the main work-flow. Let's get right to it!

Specification 2: Performing validation on a frame

The second step is to sketch main work-flow of the module. As the only responsibility of the module we're creating is to validate a frame, we decide this main work-flow to be receiving the fame and submitting it to validation.

The actual validation logic (e.g. when a frame is valid, what to do if it isn't etc.) is a separate responsibility, so we'll try postponing its implementation by pushing this responsibility to a collaborator. This collaborator, for the purpose of this spec, will appear only as a fake object without real implementation.

Create a specification

Our very first spec, written using a Given-When-Then notation, will look like this

Given any frame
When a message processing is performed for it
Then the frame should be validated according to supplied rules

Now let's try translating it literally into the code.

Given any frame

can be translated into:

var anyFrame = Any.InstanceOf<Frame>();
When a message processing is performed for it

will look like this:

var messageProcessing = new MessageProcessing();
messageProcessing.PerformFor(anyFrame);

and the last line:

Then the frame should be validated according to supplied rules

may be translated like this:

validationRules.Received().ApplyTo(frame);

So the whole spec, again:

[Fact]
public void 
ShouldValidateMessageCreatedFromFrameWithValidationRules()
{
  //GIVEN
  var anyFrame = Any.InstanceOf<Frame>();

  //WHEN
  var messageProcessing = new MessageProcessing();
  messageProcessing.PerformFor(anyFrame);

  //THEN
  validationRules.Received().ApplyTo(frame);
}

Of course, it does not compile yet, since, for instance, we have not declared any variable called validationRules. It's enough, however, to sketch the behavior and discuss the design.

If you remember last time we did this exercise, the specs told us that the approach with passing whole frame to validation led us to trouble. So let's stop for a minute to examine how we can improve the design. The Frame class is poorly encapsulated and we cannot change it to improve the encapsulation. What we can do, however, is to hide this ugly class from the rest of the application by wrapping it with our own object as soon as it enters the area under our control. Then we will be able to add domain logic into that class in order to hide its structure from general purpose logic (like validation).

Knowing all this, let's rewrite the last line of spec to include our observations:

//GIVEN
var anyFrame = Any.InstanceOf<Frame>();

//WHEN
var messageProcessing = new MessageProcessing();
messageProcessing.PerformFor(anyFrame);

//THEN
message.Received().ValidateWith(validationRules);

What's this message in the last line? It's our own wrapper around the frame. We don't have any variable by this name, nor do we have any variable named validationRules. At this point, it's not important - we're merely sketching out the idea and discovering what we need to implement this behavior. In the next stage, we'll figure out where to get all these variables and types from.

By the way, so far we have created a need to have a PerformFor() method inside MessageProcessing class, and two abstractions: message and validationRules

Note that message and validation rules take different parts in this specification: the message plays active part, since we expect some methods to be called on it. On the other hand, the validationRules is just passed around and never communicated with - its role is passive. This information will prove valuable when we get to creating these variables in the specification - stay tuned!

Make it fail for proper reason

Now, the time has come! to supply what's missing and fill the void! Mwahahahaha!

... sorry, I got a little carried away.

Anyway, to make what we have written compile, we'll have to fill the blanks. We always do it in the following order:

  1. First, we add all missing variable instantiations
  2. Then, we add all the missing interfaces and classes
  3. Finally, we add to those types and interfaces all missing methods

1. Add all missing variable instantiations

Let's see... We're missing instantiations of two variables. The first one is message. As I already wrote, message plays active role, so It's gonna be a mock:

var message = Substitute.For<Message>();

Then, there's validationRules. It plays a passive role, so It's going to be just any instance of interface ValidationRules:

var validationRules = Any.InstanceOf<ValidationRules>();

By the way, there are different ways of implementing "any instance of X" - it can even return a mock. In such case, what's the point for using this mechanism and not just create another mock? Well, remember that these specs will become our living documentation on a micro level, so it's always better to state explicitly which classes' behaviors we care about and which we don't.

Another thing we need to consider here is how the MessageProcessing is going to wrap our frame with the exact instance of Message class that we just created in our spec. We cannot pass the message to the MessageProcessing constructor (because we don't know the frame yet at this point and we want to wrap each frame with its own message) nor can we pass it through the PerformFor method (because this is the entry point for third-party and if they could pass a wrapped frame to us, we wouldn't need to know about the frame at all).

So, again, how do we make MessageProcessing use our instance of message? The response is a factory! We have to create one, then pass it to MessageProcessing and make it return the message we created in our spec when it's asked to wrap the frame we're feeding to MessageProcessing (by the way, as you see, the factory plays an active role in our spec). Putting it all together, it looks like this:

[Fact]
public void 
ShouldValidateTheFrameWrappedInMessageUsingValidationRules()
{
  //GIVEN
  var anyFrame = Any.InstanceOf<Frame>();
  var message = Substitute.For<Message>();
  var validationRules = Any.InstanceOf<ValidationRules>();
  var factory = Substitute.For<MessageFactory>();

  factory.Wrap(anyFrame).Returns(message);

  //WHEN
  var messageProcessing 
    = new MessageProcessing(factory, validationRules);
  messageProcessing.PerformFor(anyFrame);

  //THEN
  message.Received().ValidateWith(validationRules);
}

And it's a complete spec, at least from syntactical point of view. The design it points to is also very good, which we'll find out going further.

2. Add all the missing interfaces and classes

So, we added all missing variable instantiations, now we can provide the missing types (by the way, note that we discovered some new types when adding missing variable instantiations and now we can provide these as well - that's why the steps are performed in this order).

The following types are missing:

  • Message interface
  • ValidationRules interface
  • MessageFactory interface

Providing them is a piece of cake:

public interface Message
{

}

public interface ValidationRules
{

}

public interface MessageFactory
{

}

3. Add all methods that do not exist but are used in the specification

Ok, done with second step, now the final one: satisfying the needs for methods. The spec shows us that the following methods are mising:

  • Messagefactory: Message Wrap(Frame frame)
  • MessageProcessing: void PerformFor(Frame frame)
  • MessageProcessing (constructor): MessageProcessing(MessageFactory factory, ValidationRules validationRules)
  • Message: void ValidateWith(ValidationRules rules)

Let's provide them:

public class MessageProcessing
{
  public MessageProcessing(
    MessafeFactory factory, 
    ValidationRules validationRules)
  {
    throw new NotImplementedException();
  }

  void PerformFor(Frame frame)
  {
    throw new NotImplementedException();
  }
}

public interface Message //TODO implement
{
  void ValidateWith(ValidationRules rules);
}

public interface ValidationRules //TODO implement
{

}

public interface MessageFactory //TODO implement
{
  Message Wrap(Frame frame);
}

I put a TODO next to each interface that does not have an implementation - that's because we'll be adding them to our TODO list in a moment. For now, I just want to signalize it.

Also, we changed the constructor, meaning we have to update the creational specification for the MessageProcessing class, because it does not have a parameterless constructor anymore. We can deal with it in two steps: first correct the specification like this:

[Fact]
public void ShouldAllowCreatingNewInstances()
{
  //GIVEN

  //WHEN
  Action whenCreatingANewInstanceOfMessageProcessingClass
    = () => new MessageProcessing(
      Any.InstanceOf<MessageFactory>,
      Any.InstanceOf<ValidationRules>);
  
  //THEN
  Assert.DoesNotThrow(whenCreatingANewInstanceOfMessageProcessingClass);
}

and then remove the NotImplementedException from the constructor of MessageProcessing class:

  public MessageProcessing(
    MessafeFactory factory, 
    ValidationRules validationRules)
  {
    //removed throwing
  }

We're now finished with all the three steps of filling in the blanks: we added necessary variables instantiations, added definitions for missing types and provided all missing methods in those types. The spec now compiles and fails. Does this mean we're done with this stage? No, not yet! If you see at where the failure is, it points towards the PerformFor method of message processing that throws a NotImplementedException - this is not failing for proper reason, since the proper reason to fail is that everything went as planned except the expected call to ValidateWith method was not made on the message object.

After removing the exception like this:

  void PerformFor(Frame frame)
  {
    //removed throwing exception
  }

we get the result we were expecting: the specification expects a call to ValidateWith method at least once, but none was made.

Before we provide an implementation that will satisfy this need, let's see at what we currently have:

public class MessageProcessing
{
  public MessageProcessing(
    MessafeFactory factory, 
    ValidationRules validationRules)
  {
  }

  void PerformFor(Frame frame)
  {
  }
}

public interface Message //TODO implement
{
  void ValidateWith(ValidationRules rules);
}

public interface ValidationRules //TODO implement
{

}

public interface MessageFactory //TODO implement
{
  Message Wrap(Frame frame);
}

Making it pass

We're going to fill in the implementation of MessageProcessing class. I like starting workflow implementations from the end, i.e. from the expectation. In the spec, we're expecting a call to ValidateWith(validationRules) to be made against message object, so let's write that into the method:

void PerformFor(Frame frame)
{
  message.ValidateWith(validationRules);
}

Now, where do we get message from? From the factory, so let's add a previous line:

void PerformFor(Frame frame)
{
  var message = factory.Wrap(frame);
  message.ValidateWith(validationRules);
}

Where do we get the frame from? It's passed into the method. Done. Where do we get the validationRules and factory from? They're constructor arguments, so we'll have to store them as fields when an instance of MessageProcessing is created:

public MessageProcessing(
  MessafeFactory factory, 
  ValidationRules validationRules)
{
  this.validationRules = validationRules;
  this.factory = factory;
}

Done! The whole implementation of the MessageProcessing class looks like this:

public class MessageProcessing
{
  readonly MessageFactory factory;
  readonly ValidationRules validationRules;

  public MessageProcessing(
    MessafeFactory factory, 
    ValidationRules validationRules)
  {
    this.validationRules = validationRules;
    this.factory = factory;
  }

  void PerformFor(Frame frame)
  {
    var message = factory.Wrap(frame);
    message.ValidateWith(validationRules);
  }
}

And the specification passes. Now we can proceed to the next stage:

Examine TODO list

Remember we left some TODOs in the code next to each interface? Let's look at it again:

public interface Message //TODO implement
{
  void ValidateWith(ValidationRules rules);
}

public interface ValidationRules //TODO implement
{

}

public interface MessageFactory //TODO implement
{
  Message Wrap(Frame frame);
}

Now let's add them to the TODO list and cross off the implemented main work-flow:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main workflow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface

What shall we implement next? Obviouslt, there's no point in implementing ValidationRules, since it doesn't contain any methods yet, so we don't even know what behaviors we need to provide. On the other hand, we've got MessageFactory and Message - each having a single method. It makes more sense to start with the MessageFactory, since its functionality is actually about creating messages, so probably, when we finish with specifying and implementing the factory, we'll also have a class implementing the Message interface already.

Specification 3: Creating new instances of MessageFactory class

Before we can use the factory to create new messages, we need to have a concrete class implementing the MessageFactory interface (I'll name this class LocationMessageFactory). This is gonna be a simple creational specification. Let's go!

Create a specification

The Given-When-Then form of the spec is:

Given nothing
When I create a new instance of LocationMessageFactory class
Then it should not result in any kind of exception
And it should implement the MessageFactory interface

As you see, this is almost the same as the specification 1. Except for the last line. Anyway, translating the spec into the code leads us to the following:

[Fact]
public void ShouldAllowCreatingNewInstances()
{
  //GIVEN

  //WHEN
  MessageFactory factory = null;

  Action whenCreatingANewInstanceOfLocationMessageFactoryClass
    = () => 
    {
      factory = new LocationMessageFactory();
    };
  
  //THEN
  Assert.DoesNotThrow(
    whenCreatingANewInstanceOfLocationMessageFactoryClass
  );
}

Note that we did not declare the factory variable using var keyword, but as a base type. This is also a part of specification - it says that LocationMessageFactory is a subtype of MessageFactory.

Make it fail for proper reason

This spec created a need to have a LocationMessageFactory class that implements MessageFactory interface and has a parameterless constructor. Let's provide it then!

public class LocationMessageFactory : MessageFactory
{
  public LocationMessageFactory()
  {
    throw new Exception();
  }

  public Message Wrap(Frame frame)
  {
    throw new NotImplementedException();
  }
}

Note two things: first, we put an exception into the constructor, so that the spec we created can fail on assertion (Assert.DoesNotThrow). The second thing to note - the interface signature forced us to provide an implementation for a method called Wrap - currently it throws NotImplementedException and is out of scope of the current specification. By the way, I treat all NotImplementedExceptions as TODO list items - we'll take care of it when we examine our TODO list in a minute. For now, the spec fails for proper reason, so let's get to the next stage.

Make it pass

We make this spec pass by removing the constructor we introduced earlier. Remember that we don't have to touch the Wrap method, since it's out of scope of current specification. The code looks like this:

public class LocationMessageFactory : Messagefactory
{
  public Message Wrap(Frame frame)
  {
    throw new NotImplementedException();
  }
}

Examine TODO list

We can cross off the item related to implementing MessageFactory class. Now we have all the initial items crossed off, but another one popped out in the meantime - the NotImplementedException inside the Wrap method - it clearly points that we need to provide a behavior over there.

Our current TODO list:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main work-flow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class

The newly added item on the TODO list is our next target.

Specification 4: wrapping frames with messages

Let's implement the Wrap method in LocationMessageFactory so that it actually creates something useful for us.

Create a specification

A Given-When-Then form of the spec looks like this:

Given a factory
And any frame
When I ask the factory to wrap the frame
Then it should create a LocationMessage object from the frame

Which translates into the following code:

[Fact]
public void ShouldWrapFramesWithLocationMessageObjects()
{
  //GIVEN
  var factory = new LocationMessageFactory();
  var anyFrame = Any.InstanceOf<Frame>();

  //WHEN
  var result = factory.Wrap(anyFrame);
  
  //THEN
  Assert.IsType<LocationMessage>(result);
}

There's one thing that might seem wierd about this spec - we specify nowhere that the message is wrapping the particular frame we pass to it - it can just create another one or just wrap nothing. Is it wrong? I think not - the creational specs are always awkward and you can almost never specify entirely from which objects another object is created. We will just have to trust the production code that it wraps the frame (by the way, there are some cases where object construction rules are so complex that we DO want to specify them in detail, but this is not such a case).

Make it fail for proper reason

The spec creates a need for a new type - a LocationMessage. An instance of this type needs to be created by the factory in order to fulfill this spec. That's why we won't have to write a separate creational specification for creating LocationMessage objects - we're specifying everything we need in the factory specification already.

Anyway, the first thing to do is to satisfy the newly introduced need and create a LocationMessage. It needs to implement the Message interface, otherwise the code won't compile. Here's the implementation of the LocationMessage class:

public class LocationMessage : Message
{
  public LocationMessage(Frame frame)
  {
    //We'll need this anyway, so I'm adding it now.
  }

  void ValidateWith(ValidationRules rules)
  {
    throw new NotImplementedException();
  }
}

I added a constructor, although it wasn't forced directly by the specification (such cases should be extremaly rare). Also, implementing the Message interface forced us to provide an implementation of the ValidateWith method. For now we don't care about it, since it's out of scope of the current specification, but we'll be adding it to our TODO list shortly.

Even though we needed the LocationMessage to make the compilation pass, we won't be using it in the factory implementation just yet. The specification expects an object of type LocationMessage to pass, so in order to fail for proper reason, we'll have to make the factory return something different. The quick choice for such cases is null:

public class LocationMessageFactory : Messagefactory
{
  public Message Wrap(Frame frame)
  {
    return null;
  }
}

Ok, the specification expects an instance of type LocationMessage, but gets a null instead - the spec fails on assertion, which is proper reason for it to fail and it means it's time to move on to the next stage.

Make it fail for proper reason

In order to do this, we'll just have to return an instance of LocationMessage type and use the constructor we have created:

public class LocationMessageFactory : Messagefactory
{
  public Message Wrap(Frame frame)
  {
    return new LocationMessage(frame);
  }
}

Finished! Now to check the TODO list!

Examine TODO list

We can cross off the item related to implementing Wrap method as well as implementing Message interface. Also, by implementing the Message interface with LocationMessage class, which, just to remind you, looks like this:

public class LocationMessage : Message
{
  public LocationMessage(Frame frame)
  {
    //We don't need to use the frame just yet
  }

  void ValidateWith(ValidationRules rules)
  {
    throw new NotImplementedException();
  }
}

we discovered that we need to supply implementation to the ValidateWith method, which currently throws a NotImplementedException. This item should be added to our list.

So, to sum up, the list looks like this:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main work-flow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class

We already know that we have three fields in the class: Speed, Age and Sender, so we can add more details to the last item and split it into three:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main workflow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class for Speed field
  8. Implement behavior required from ValidateWith method in LocationMessage class for Age field
  9. Implement behavior required from ValidateWith method in LocationMessage class for Sender field

Again, there's no sense in picking ValidationRules interface implementation, since it has no methods, so let's take the three last items, one by one.

Specification 5: Submit Speed field to validation

As I stated previously, the reason Message abstraction exists is to decouple validation rules from the frame structure. The choice of which validation rule to apply to which frame field should be made by implementations of the Message interface - i.e. LocationMessage. The first field that needs to be passed to a validation rule is Speed.

Create a specification

Again, let's use a Given-When-Then notation, to write down the following:

Given any frame
And a location message wrapping that frame
And validation rules
When I validate the message using the validation rules
Then validation rule for integer values should be applied to the Speed field

Translated into code, it looks like this:

[Fact]
public void ShouldPerformValidationForSpeedFieldWhenValidated()
{
  //GIVEN
  var anyFrame = Any.InstanceOf<Frame>();
  var message = new LocationMessage(anyFrame);
  var validationRules = Substitute.For<ValidationRules>();
  
  //WHEN
  message.ValidateWith(validationRules);

  //THEN 
  validationRules.Received().ApplyTo(anyFrame.Speed);
}

Note that this is actually the first time we're referencing a field of the Frame class! What's more, we expect it to be passed into the validation rules which don't know that the passed value belongs to the frame. Thus, we have managed to successfully encapsulate the frame structure inside the LocationMessage class and decouple it from validation rules.

Make it fail for proper reason

The specification created a need for one new method inside VlidationRules interface: ApplyTo with an int argument. To satisfy this need, let's provide the necessary signature inside the ValidationRules interface:

public interface ValidationRules
{
  void ApplyTo(int intValue);
}

This is great news, because up to now, the ValidationRules interface was empty and we had no clue what to do with it. Now we do, but we'll leave it for later as currently the implementation of ApplyTo method is out of scope.

Another thing to do is to remove the NotImplementedException from the ValidateWith method inside the LocationMessage class. Done. Now it looks like this:

public class LocationMessage : Message
{
  public LocationMessage(Frame frame)
  {
    //We don't need to use the frame just yet
  }

  void ValidateWith(ValidationRules rules)
  {
    
  }
}

The spec fails because a call to ApplyTo method with specific int value was expected on the validationRules, but was not performed, which means that the spec fails for proper reason.

Make it pass

The implementation that makes our code fulfill the spec is really easy, so I'll just type it in:

public class LocationMessage : Message
{
  private readonly Frame wrappedFrame;

  public LocationMessage(Frame frame)
  {
    wrappedFrame = frame; //added
  }

  void ValidateWith(ValidationRules rules)
  {
    rules.ApplyTo(frame.Speed); //added  
  }
}

And that's it.

Examine TODO list

We can cross off Speed field:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main work-flow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class for Speed field
  8. Implement behavior required from ValidateWith method in LocationMessage class for Age field
  9. Implement behavior required from ValidateWith method in LocationMessage class for Sender field

Looking at the TODO list, it should be very easy to implement the Age field validation, as it's an integer, just like Speed, which we just finished implementing. Let's take it on then!

Specification 6: Submit Age field to validation

Create a specification

The spec is going to be almost the same as previously, so all we need to do is copy the previous one and make a change or two. Hey, we're copy-pasting here! Let's use this as an opportunity to perform an experiment - we'll make an error by correcting only the name of the pasted specification, leaving the validated field name as Speed (not Age, which should be here instead) and watch whether we can get away with it:

[Fact]
public void ShouldPerformValidationForAgeFieldWhenValidated()
{
  //GIVEN
  var anyFrame = Any.InstanceOf<Frame>();
  var message = new LocationMessage(anyFrame);
  var validationRules = Substitute.For<ValidationRules>();
  
  //WHEN
  message.ValidateWith(validationRules);

  //THEN 
  //Oh, we forgot to change Speed to Age...
  validationRules.Received().ApplyTo(anyFrame.Speed);
}

What happens? The spec passes right away - a warning sign!

Test-first has this advantage when compared to test-after, that we always validate the specification by letting it fail at first for proper reason. When a specification passes right away after being written, then it's a warning sign and we need to investigate what's going on.

It feels really good to be protected somehow from copy-pasting errors :-). Let's quickly correct the spec:

[Fact]
public void ShouldPerformValidationForAgeFieldWhenValidated()
{
  //GIVEN
  var anyFrame = Any.InstanceOf<Frame>();
  var message = new LocationMessage(anyFrame);
  var validationRules = Substitute.For<ValidationRules>();
  
  //WHEN
  message.ValidateWith(validationRules);

  //THEN 
  //corrected:
  validationRules.Received().ApplyTo(anyFrame.Age);
}

There, this should do it - the spec fails on mock verification which is what we were aiming at.

Some of you may notice that I'm not using Setup and Teardown kind of methods. This is on purpose - not only do Setup and Teardown make the tutorial hard to follow by splitting specifications into several methods, they also have other problems. So for me, a better (and yes - more maintainable!) way is even to copy-paste existing specification and make some adjustments that to use Setup and Teardown. Maybe someday I'll write a post on that. In the meantime you can look for some arguments from both sides of the fence in the internet, as such approach has its proponents and opponents.

Another question that may be raised is: why don't I write one specifications for all the fields, but a separate spec for each of them? Actually, there's no big deal about that. The main reason is that in case I did one specification for all the fields, I would have to name it something like ShouldApplyValidationRulesToAllFields() - it would not tell me which rules apply to which field. I like to think of unit test tool report (which consists of unit test names) as a form of documentation and by separating the specifications for each field, I make this documentation more verbose.

Make it fail for proper reason

The specification already fails for proper reason. We're expecting validation rules to be applied to field named Age, but there's no such logic inside the LocationMessage's ValidateWith method's implementation.

Make it pass

Just add one line of code and we're all set:

public class LocationMessage : Message
{
  private readonly Frame wrappedFrame;

  public LocationMessage(Frame frame)
  {
    wrappedFrame = frame;    
  }

  void ValidateWith(ValidationRules rules)
  {
    rules.ApplyTo(frame.Speed);
    rules.ApplyTo(frame.Age); //added this line
  }
}

Ok, it passes - now, wasn't that easy?

Examine TODO list

We can cross off another item from the TODO list - the one about Age field, leaving us with the following:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main work-flow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class for Speed field
  8. Implement behavior required from ValidateWith method in LocationMessage class for Age field
  9. Implement behavior required from ValidateWith method in LocationMessage class for Sender field

Only two choices left. Since we already began with the ValidateWith method, let's take on the last one from this series - the one related to Sender field.

Specification 7: Submit Sender field to validation

This case is going to be pretty much the same as with both previous fields, only this time we'll be handling a string instead of an integer.

Create a specification

In order to create a specification in a Given-When-Then notation, let's write down the following:

Given any frame
And a location message wrapping that frame
And a validation
When I validate the message using the validationRules
Then validation rule for string values should be applied to the Sender field

The spec is going to look pretty much the same as two previous ones:

[Fact]
public void ShouldPerformValidationForSenderFieldWhenValidated()
{
  //GIVEN
  var anyFrame = Any.InstanceOf<Frame>();
  var message = new LocationMessage(anyFrame);
  var validationRules = Substitute.For<ValidationRules>();
  
  //WHEN
  message.ValidateWith(validationRules);

  //THEN 
  validationRules.Received().ApplyTo(anyFrame.Sender);
}

Make it fail for proper reason

As I said, the only difference is that this time, Sender is a string value. Yet we still use the ApplyTo name for a method expected to be called, although its declaration looks like this:

public interface ValidationRules
{
  void ApplyTo(int intValue);
}

Thus, the spec won't compile. It means that we created a need for an overload of the ApplyTo method, taking a string argument:

public interface ValidationRules
{
  void ApplyTo(int intValue);
  void ApplyTo(string stringValue); //added line
}

That makes our spec compile and fail for proper reason - we were expecting ApplyTo method to be called, but it wasn't.

Make it pass

The implementation of this spec is going to be as easy as the previous one. Just watch:

public class LocationMessage : Message
{
  private readonly Frame wrappedFrame;

  public LocationMessage(Frame frame)
  {
    wrappedFrame = frame;    
  }

  void ValidateWith(ValidationRules rules)
  {
    rules.ApplyTo(frame.Speed);
    rules.ApplyTo(frame.Age);
    rules.ApplyTo(frame.Sender); //added this line
  }
}

Ok, that's it.

One may argue that using the same name for different validation methods does not provide enough readability, because when looking at the implementation of ValidateWith method, one can't really tell that two different validation rules are being applied - it looks like it's always one. This is a valid argument and one may consider giving the validation methods distinct names, such as ApplyToInt for integers and ApplyToString for strings. For this kata, I'll leave the overloads, since it doesn't really matter so much.

Examine TODO list

Another item to cross off from our TODO list, this time for implementing the Sender field:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main workflow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class for Speed field
  8. Implement behavior required from ValidateWith method in LocationMessage class for Age field
  9. Implement behavior required from ValidateWith method in LocationMessage class for Sender field

which leaves us with only one item: implementation of the ValidationRules interface.

Specification 8: Creating new instances of SimpleValidationRules class

We decide that the implementation of the ValidationRules interface will be called SimpleValidationRules. We need to drive the existence of this class and the following Given-When-Then specification will help us with this task:

Given nothing
When I create a new instance of SimpleValidationRules class
Then it should not result in any kind of exception

Without further comments, let's take it to the code:

[Fact]
public void ShouldAllowCreatingNewInstances()
{
  //GIVEN

  //WHEN
  ValidationRules rules = null;

  Action whenCreatingANewInstanceOfSimpleValidationRulesClass
    = () => 
    {
      rules = new SimpleValidationRules();
    };
  
  //THEN
  Assert.DoesNotThrow(
    whenCreatingANewInstanceOfSimpleValidationRulesClass
  );
}

Make it fail for proper reason

We created a need to have a SimpleValidationRules class implementing ValidationRules interface. To satisfy this need, we'll have to create this class. Here we go:

public class SimpleValidationRules : ValidationRules
{
  public void SimpleValidationRules()
  {
    throw new NotImplementedException();
  }

  public void ApplyTo(int intValue)
  {
    throw new NotImplementedException();
  }

  public void ApplyTo(string stringValue)
  {
    throw new NotImplementedException();
  }
}

As you see, the interface signature forced us to implement ApplyTo method in two flavors. We do not need to concern ourselves with that yet, but we'll get back to it when evaluating TODO list.

For now, the spec fails on assertion, i.e. for a proper reason. It means that we can proceed with the next stage. By the way, I put an exception in the constructor again just to make the spec fail - if I didn't introduce the constructor at all, it would probably be green by now. Just to remind you, this is to make a point that we can follow a strict set of steps almost mechanically and that specification failing for proper reason is so valuable as a source of feedback, that we're willing to put in a bit of extra code just to attain it.

Make it pass

Piece of cake - just remove the constructor:

public class SimpleValidationRules : ValidationRules
{
  public void ApplyTo(int intValue)
  {
    throw new NotImplementedException();
  }

  public void ApplyTo(string stringValue)
  {
    throw new NotImplementedException();
  }
}

And done - the spec passes. No further comments needed.

Examine TODO list

Fulfilling this specification led us to discovering a new class with two methods not yet implemented - we need to add them. Also, we can cross off implementing ValidationRules interface, since we just did it:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main work-flow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class for Speed field
  8. Implement behavior required from ValidateWith method in LocationMessage class for Age field
  9. Implement behavior required from ValidateWith method in LocationMessage class for Sender field
  10. Implement behavior required from ApplyTo method in SimpleValidationRules class for integer values
  11. Implement behavior required from ApplyTo method in SimpleValidationRules class for string values

But this is not end yet! Let's remind ourselves what exactly hides below these two newly added items by looking back at the table from the exercise description:

type of field Correctness criteria When satisfied When not satisfied
int greater than 0 do nothing throw exception
string not null and not empty do nothing throw exception

From the table, it looks like we have the following exact behaviors to specify and implement inside SimpleValidationRules class:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main work-flow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class for Speed field
  8. Implement behavior required from ValidateWith method in LocationMessage class for Age field
  9. Implement behavior required from ValidateWith method in LocationMessage class for Sender field
  10. SimpleValidationRules should throw exception when applied to integer less than or equal 0
  11. SimpleValidationRules should not throw exception when applied to integer greater than 0
  12. SimpleValidationRules should throw exception when applied to null string
  13. SimpleValidationRules should throw exception when applied to empty string
  14. SimpleValidationRules should not throw exception when applied to string that's neither null nor empty

When we look at the TODO items, there is one more thing that attracts our attention - it's the '0' in both items related to integer validation. In contrast to null and empty string, 0 is not a special kind of value here - it's a number like any other. It may be 0 today, and 5 tomorrow. Leaving it in two specifications will lead us to maintaining two specs whenever this number changes. That's why we'll extract the requirement for this value to be 0 into a separate TODO list item. At the same time, we'll rewrite the two items to be more general:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main work-flow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class for Speed field
  8. Implement behavior required from ValidateWith method in LocationMessage class for Age field
  9. Implement behavior required from ValidateWith method in LocationMessage class for Sender field
  10. SimpleValidationRules should throw exception when applied to integer less than minimum allowed integer
  11. SimpleValidationRules should not throw exception when applied to integer greater or equal to minimum allowed integer
  12. SimpleValidationRules should treat 1 as minimum allowed integer
  13. SimpleValidationRules should throw exception when applied to null string
  14. SimpleValidationRules should throw exception when applied to empty string
  15. SimpleValidationRules should not throw exception when applied to string that's neither null nor empty

The only thing to note here is that we changed 0 to 1 while adjusting the greater/less conditions (what was previously less than or equal 0, now is less than 1 etc.). We could keep the 0, but thinking in terms of "minimum allowed value" (which is 1) is easier for me than in terms of "maximum disallowed value" (which is 0). You may choose to do otherwise when you perform this kata on your own.

Let's take on the first unimplemented item.

Specification 9: Throwing exceptions when applied to integers that are less than minimum allowed integer value

From now on, we'll move forward without mocks, as we've reached the border of the system. Most of the specification we'll be writing are called functional specifications (as opposed to mock-based work-flow specifications and creational specifications that we were doing so far) and a little bit different practices apply to this kind of specs, as we'll shortly see. Also, we'll speed up a little with more obvious parts.

Create a specification

Our specification in the Given-When-Then form:

Given simple validation rules
When I apply them to an integer value less than minimum allowed integer by at least 1
Then an exception should be thrown

This is pretty straightforward. Translating the spec into the code leaves us with the following:

[Fact]
public void 
ShouldThrowExceptionWhenValidatedIntegerIsBelowAllowedMinimum()
{
  //GIVEN
  var rules = new SimpleValidationRules();
  var integerBelowAllowedMinimum 
    = SimpleValidation.MinimumAllowedInteger - 1;

  //WHEN
  Action applyingRulesToIntegerBelowAllowedMinimum 
    = () => rules.ApplyTo(integerBelowAllowedMinimum);

  //THEN
  Assert.Throws<Exception>(applyingRulesToIntegerBelowAllowedMinimum);
}

Why did we use SimpleValidation.MinimumAllowedInteger - 1? because it's the thinnest possible boundary between two behaviors - throwing when value is invalid and not throwing when it's valid. You can read more on this in a great post by Amir Kolsky and Scott Bain.

Now, let's see what's missing...

Making it fail for proper reason

As it stands now, the code does not compile. We're missing the SimpleValidation.MinimumAllowedInteger constant (since the above spec is the first place in the code where it actually appears). Let's introduce it then:

public class SimpleValidationRules : ValidationRules
{
  public const int MinimumAllowedInteger = 12345; //TODO

  public void ApplyTo(int intValue)
  {
    throw new NotImplementedException();
  }

  public void ApplyTo(string stringValue)
  {
    throw new NotImplementedException();
  }
}

By giving this constant a value of 12345 and placing a TODO next to it, we're signalizing that it doesn't really matter for now what the value of this constant is, but we'll need to take care of it later (by the way, it's already on our TODO list - remember?).

This time the spec not only compiles, but it also passes, thanks to a NotImplementedException thrown from inside of ApplyTo method. I'm sorry, but you know the rules - we have to make it fail :-). In order to do so, we'll remove throwing the mentioned NotImplementedException:

public class SimpleValidationRules : ValidationRules
{
  public const int MinimumAllowedInteger = 12345; //TODO

  public void ApplyTo(int intValue)
  {
    //removed throwing exception from here
  }

  public void ApplyTo(string stringValue)
  {
    throw new NotImplementedException();
  }
}

Great, now the spec fails for the correct reason - we were expecting a call to ApplyTo method to throw an exception, but nothing was thrown.

Make it pass

The specification expects an exception to be thrown, so let's throw it! Only this time, as opposed to the previous throw that was present in the ApplyTo method, we're gonna throw an object of class Exception, not NotImplementedException:

public class SimpleValidationRules : ValidationRules
{
  public const MinimumAllowedInteger = 12345; //TODO

  public void ApplyTo(int intValue)
  {
    throw new Exception(); //added line
  }

  public void ApplyTo(string stringValue)
  {
    throw new NotImplementedException();
  }
}

And we're done!

"Are we really done here?" - one might argue. This logic does not validate anything - it just throws an exception! That's true, however, we have to remember that we only do what's necessary to make the existing specs pass. Every specification introduces a behavioral distinction and we have not yet introduced a specification that tells us when not to throw. We should add such specification to the TODO list - oh, actually, we already did that! We'll try to fulfil it in a minute, just after we examine our TODO list.

Examine TODO list

We can cross off throwing exception when validated integer is below allowed minimum from our TODO list:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main work-flow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class for Speed field
  8. Implement behavior required from ValidateWith method in LocationMessage class for Age field
  9. Implement behavior required from ValidateWith method in LocationMessage class for Sender field
  10. SimpleValidationRules should throw exception when applied to integer less than minimum allowed integer
  11. SimpleValidationRules should not throw exception when applied to integer greater or equal to minimum allowed integer
  12. SimpleValidationRules should treat 1 as minimum allowed integer
  13. SimpleValidationRules should throw exception when applied to null string
  14. SimpleValidationRules should throw exception when applied to empty string
  15. SimpleValidationRules should not throw exception when applied to string that's neither null nor empty

Now let's specify when the exception should not be thrown.

Specification 10: not throwing exception when validated integer is at least minimum allowed integer

First, a Given-When-Then specification:

Given simple validation rules
When I apply them to an integer value less than minimum allowed integer by at least 1
Then an exception should be thrown

Second, its translation into the code:

[Fact]
public void 
ShouldNotThrowAnyExceptionWhenValidatedIntegerIsAtLeastAllowedMinimum()
{
  //GIVEN
  var rules = new SimpleValidationRules();
  var integerAtLeastOfMinimumAllowedValue
    = SimpleValidation.MinimumAllowedInteger;

  //WHEN
  Action applyingRulesToIntegerAtLeastOfAllowedMinimum 
    = () => rules.ApplyTo(integerAtLeastOfMinimumAllowedValue);

  //THEN
  Assert.DoesNotThrow(applyingRulesToIntegerAtLeastOfAllowedMinimum);
}

We picked SimpleValidation.MinimumAllowedInteger value for this specification because it's a boundary value for specified behavior. Now to make it fail for proper reason...

Make it fail for proper reason

Actually... it already fails for proper reason - the specification expects that no exception is thrown, but it's thrown. All we need to do is to...

Make it pass

Remember that this is a second specification that passes through the ApplyTo method with int argument. Thus, while implementnig this one, we have to take care not to make the previous one fail. The boundary between the two behaviors described by the specs is the SimpleValidation.MinimumAllowedInteger, so let's turn this knowledge into an if statement:

public class SimpleValidationRules : ValidationRules
{
  public const int MinimumAllowedInteger = 12345; //TODO

  public void ApplyTo(int intValue)
  {
    if(intValue < MinimumAllowedInteger) //added
    {                                       //added
      throw new Exception();
    }                                       //added
  }

  public void ApplyTo(string stringValue)
  {
    throw new NotImplementedException();
  }
}

Now both specs pass, which means we can go on.

Examine TODO list

We can cross off another item on the TODO list - the one related to not throwing exceptions when validating integer that's at least of allowed minimum integer value:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main work-flow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class for Speed field
  8. Implement behavior required from ValidateWith method in LocationMessage class for Age field
  9. Implement behavior required from ValidateWith method in LocationMessage class for Sender field
  10. SimpleValidationRules should throw exception when applied to integer less than minimum allowed integer
  11. SimpleValidationRules should not throw exception when applied to integer greater or equal to minimum allowed integer
  12. SimpleValidationRules should treat 1 as minimum allowed integer
  13. SimpleValidationRules should throw exception when applied to null string
  14. SimpleValidationRules should throw exception when applied to empty string
  15. SimpleValidationRules should not throw exception when applied to string that's neither null nor empty

To finish off the integer validation functionality, let's take on treating 1 as minimum allowed integer.

Specification 11: 1 should be used as minimum valid integer

This time, to breathe a bit of fresh air, it's gonna be a constant specification. We'll go faster with this one as it's a really obvious to specify and implement. We don't even have to come up with a Given-When-Then specification.

Here's the spec:

[Fact]
public void 
ShouldTreat1AsMinimumAllowedInteger()
{
  Assert.Equal(1, SimpleValidationRules.MinimumAllowedInteger);
}

This fails for proper reason straight away, because the spec expects 1, but it gets 12345, so let's make a change to make it pass:

public class SimpleValidationRules : ValidationRules
{
  public const MinimumAllowedInteger = 1;

  //... the two ApplyTo methods ...
}

Done! we can cross off another item from our TODO list:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main work-flow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class for Speed field
  8. Implement behavior required from ValidateWith method in LocationMessage class for Age field
  9. Implement behavior required from ValidateWith method in LocationMessage class for Sender field
  10. SimpleValidationRules should throw exception when applied to integer less than minimum allowed integer
  11. SimpleValidationRules should not throw exception when applied to integer greater or equal to minimum allowed integer
  12. SimpleValidationRules should treat 1 as minimum allowed integer
  13. SimpleValidationRules should throw exception when applied to null string
  14. SimpleValidationRules should throw exception when applied to empty string
  15. SimpleValidationRules should not throw exception when applied to string that's neither null nor empty

Ok, the last functionality to implement is the one related to the string validation rules. Let's go!

Specification 12: throwing exceptions when validated string is null

This case is very similar to throwing exceptions during integer validations. If you're bored reading this, you can just skim through this section briefly as there's nothing new to learn here.

Create a specification

Our Given-When-Then specification looks like this:

Given simple validation rules
When I apply them to a null string
Then an exception should be thrown

which translates into:

[Fact]
public void 
ShouldThrowExceptionWhenAppliedToNullString()
{
  //GIVEN
  var rules = new SimpleValidationRules();
  string nullString = null;

  //WHEN
  Action applyingRulesToNullString
    = () => rules.ApplyTo(nullString);

  //THEN
  Assert.Throws<Exception>(applyingRulesToNullString);
}

No new methods or classes needed to compile this. Also, it already passes because currently the implementation of ApplyTo for strings already throws an exception:

  public void ApplyTo(string stringValue)
  {
    throw new NotImplementedException();
  }

Let's make it fail for proper reason.

Make it fail for proper reason

We can achieve this by removing throwing the exception from the ApplyTo method like this:

public class SimpleValidationRules : ValidationRules
{
  public const int MinimumAllowedInteger = 1;

  public void ApplyTo(int intValue)
  {
    if(intValue < MinimumAllowedInteger)
    {
      throw new Exception();
    }
  }

  public void ApplyTo(string stringValue)
  {
    //removed throwing NotImplementedException
  }
}

The specification expects that exception is thrown, but none is, so the failure is for proper reason.

Make it pass

Putting an exception back (but not NotImplementedException, since we mark TODO items with these) will do it:

public class SimpleValidationRules : ValidationRules
{
  public const int MinimumAllowedInteger = 1;

  public void ApplyTo(int intValue)
  {
    if(intValue < MinimumAllowedInteger)
    {
      throw new Exception();
    }
  }

  public void ApplyTo(string stringValue)
  {
    throw new Exception();
  }
}

The spec passes now, so we're all happy - time to move on.

Examine TODO list

Another item to get rid of from the TODO list - the one related to throwing exception when null string is validated:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main work-flow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class for Speed field
  8. Implement behavior required from ValidateWith method in LocationMessage class for Age field
  9. Implement behavior required from ValidateWith method in LocationMessage class for Sender field
  10. SimpleValidationRules should throw exception when applied to integer less than minimum allowed integer
  11. SimpleValidationRules should not throw exception when applied to integer greater or equal to minimum allowed integer
  12. SimpleValidationRules should treat 1 as minimum allowed integer
  13. SimpleValidationRules should throw exception when applied to null string
  14. SimpleValidationRules should throw exception when applied to empty string
  15. SimpleValidationRules should not throw exception when applied to string that's neither null nor empty

Great - only two more to go! We're almost there! Let's pick up the next item - throwing exception on empty string.

Specification 13: throwing exceptions when validating empty string

The Given-When-Then specification is almost the same as the previous one:

Given simple validation rules
When I apply them to an empty string
Then an exception should be thrown

which translates into:

[Fact]
public void 
ShouldThrowExceptionAppliedToEmptyString()
{
  //GIVEN
  var rules = new SimpleValidationRules();
  string nullString = null;

  //WHEN
  Action applyingRulesToNullString
    = () => rules.ApplyTo(nullString);

  //THEN
  Assert.Throws<Exception>(applyingRulesToNullString);
}

This specification compiles and passes instantly. As you remember, we have to make it fail for proper reason. But wait, this time we cannot remove throwing the exception, because the previous specification will fail. What are we gonna do?

Make it fail for proper reason

You won't like this probably, but we'll add temporary code to ApplyTo method just to make this one specification fail.

Here's this code:

  public void ApplyTo(string stringValue)
  {
    if(stringValue != string.Empty) //added temporary code
    {                               //added temporary code
      throw new Exception();
    }                               //added temporary code
  }

You may think I'm insane to put in so much code just to make a specification fail, but remember I'm trying to make a point during this kata ;-).

Make it pass

Now that we know that the spec can fail for proper reason, we can revert the changes we just made and get back to the previous implementation that was actually good enough :-).

  public void ApplyTo(string stringValue)
  {
    // this is good enough to pass the current spec
    // and the previous one.
    throw new Exception();
  }

You may think this is really funny - we made some effort just to revert it back. What we gained from it is a new specification and a certainty that it can fail when it's not fulfilled.

Examine TODO list

Another item to cross off:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main work-flow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class for Speed field
  8. Implement behavior required from ValidateWith method in LocationMessage class for Age field
  9. Implement behavior required from ValidateWith method in LocationMessage class for Sender field
  10. SimpleValidationRules should throw exception when applied to integer less than minimum allowed integer
  11. SimpleValidationRules should not throw exception when applied to integer greater or equal to minimum allowed integer
  12. SimpleValidationRules should treat 1 as minimum allowed integer
  13. SimpleValidationRules should throw exception when applied to null string
  14. SimpleValidationRules should throw exception when applied to empty string
  15. SimpleValidationRules should not throw exception when applied to string that's neither null nor empty

Now, it's time for the last one and we're finished!

Specification 13: not throwing exception when validated string is neither null nor empty

Create a specification

The last specification in a Given-When-Then form:

Given simple validation rules
When I apply them to a string that's neither null nor empty
Then no exception should be thrown

which translates into:

[Fact]
public void 
ShouldNotThrowExceptionWhenAppliedToAStringThatIsNeitherNullNorEmpty()
{
  //GIVEN
  var rules = new SimpleValidationRules();
  string notNullNotEmptyString = Any.MeaningfulString();

  //WHEN
  Action applyingRulesToNotNullNotEmptyString
    = () => rules.ApplyTo(notNullNotEmptyString);

  //THEN
  Assert.DoesNotThrow(applyingRulesToNotNullNotEmptyString);
}

Make it fail for proper reason

It already compiles and fails for proper reason - the specification is expecting no exception, but one is thrown so nothing needs to be done at this stage.

Make it pass

Currently, the implementation of ApplyTo method looks like this:

  public void ApplyTo(string stringValue)
  {
    throw new Exception();
  }

I.e. it always throws. What we want is to make it not throw when passed string is neither null nor empty. Actually, implementing it is quite easy:

  public void ApplyTo(string stringValue)
  {
    if(!string.IsNullOrEmpty(stringValue)) //added
    {                                      //added
      throw new Exception();
    }                                      //added
  }

This makes our final specification pass.

Examine TODO list

We cross off the final item from TODO list:

  1. Create entry point to the module (top-level abstraction)
  2. Implement main workflow of the module
  3. Implement Message interface
  4. Implement MessageFactory interface
  5. Implement ValidationRules interface
  6. Implement behavior required from Wrap method in LocationMessageFactory class
  7. Implement behavior required from ValidateWith method in LocationMessage class for Speed field
  8. Implement behavior required from ValidateWith method in LocationMessage class for Age field
  9. Implement behavior required from ValidateWith method in LocationMessage class for Sender field
  10. SimpleValidationRules should throw exception when applied to integer less than minimum allowed integer
  11. SimpleValidationRules should not throw exception when applied to integer greater or equal to minimum allowed integer
  12. SimpleValidationRules should treat 1 as minimum allowed integer
  13. SimpleValidationRules should throw exception when applied to null string
  14. SimpleValidationRules should throw exception when applied to empty string
  15. SimpleValidationRules should not throw exception when applied to string that's neither null nor empty

and we're all set! Congratulations - you managed to get with me through this lengthy tutorial :-)

Now, there are few things we need to discuss before we finish

1. What's "better" in this implementation than in the previous, "worse" one?

Compared to the previous approach, we wrote 13 specifications as opposed to 8 last time. This means that we wrote 5 more specs! What's the return of investment?

Let's compare the two solutions against some exemplary changes:

Exemplary change Previous solution New solution
Field int Longitude is added to the frame Maintain 4 existing specs, write 1 new Write 1 new spec
New validation rule is added for Speed field that it has to be less than 100 Maintain 4 existing specs, write 1 new Write 3 new specs
The existing validation rule for integers changes so that now they have to be less than 0 instead of more than 0 Maintain 4 existing specs Maintain 2 existing specs

The difference grows as more fields and more validation rules are added and the advantage of the approach described in this post becomes more obvious. If you don't believe me, try it out and see for yourself.

2. What about refactoring?

That's right - the TDD cycle is red-green-refactor, but I didn't even mention the last one during the kata. This was done on purpose - let me explain myself :-). With the previous, screwed up approach to this kata, I stated that what I wrote should be refactored, but I'd start from scratch next time anyway. So this time I started from scratch and made it so that no refactoring is necessary. This is because most of the TDD tutorials I saw that involve refactoring are hard to follow. So I traded off showing full TDD cycle for the example being easy to follow and understand. In normal circumstances (not educational ones), I'd probably go with the approach shown earlier and refactor to this approach when the specifications would tell me that the design contains smells.

Another reason is that the kata shows a single slice of functionality, and no incremental scope pulling is taking place.

Maybe someday I'll write a post on refactoring so that we get from previous attempt to this one. For now, I'm skipping it.

3. Can't we abstract the invalid values for strings? Isn't the current solution a code smell?

By the way, if you look at some parts of the solution, namely the string validation, you can spot that it can be further abstracted. Instead of hardcoding two cases where a string is invalid (null and empty string), we could turn it into a list of invalid values and implement a general mechanism inside SimpleValidationRules that compares a validated string with such list. This would make the specs even more maintainable, but I consider it an overdesign. Not every mechanism is worth abstracting away and nothing points that more than two values will be forbidden. Of course, if this assumption doesn't hold in the future, the specs will tell me that. For now, I prefer keeping this part simple.

Summary

I hope this post is of any use for anyone - I made a lot of effort to put it together. Of course, it lacks some aspects of TDD (e.g. acceptance specifications or refactoring), but should give a general feel of how we can derive design and responsibilities using executable specifications and test-first approach.

By the way, the post is so long that I probably made at least few mistakes when writing it. If you see any of those, please let me know. Also, I welcome any feedback - feel free to leave a comment!

That's all for now - see ya!