var blog = new ThoughtStream(me); RSS 2.0
 Thursday, February 19, 2009

I have a service object with an interface explicitly defined for it. I like this because it let’s me unit test the things that need the service without having to worry about the implementation detail of the actual service.

public interface IMyService
{
  public void DoSomething();
  public void AnotherThingHere();
}

When I get to the implementation of this service and I start specifying the behavior through my specification/tests, I create a class that has a dependency on another interface – ISomeRepository. This repository is used in both methods of the actual service implementation.

For the “AnotherThingHere” method, I end up with several specification/tests because that method has some good business logic in it.

For the “DoSomething” method, though, the real implementation is only a pass-through to the repository and my specification/test ends up looking like this:

[TestFixture]
public class When_doing_something: ContextSpecification
{
 
 ISomeRepository repo;
 
 public override void Context()
 {
   repo = MockRepository.GenerateMock<ISomeRepository>();
   IMyService myService = new MyService(repo);
 
   myService.DoSomething();
 }
 
 [Test]
 public void Should_do_something()
 {
   repo.AssertWasCalled(r => r.DoSomething());
 }
 
}

I know this specification is necessary because I am using the “DoSomething” method of IMyService in other parts of the system. I think there is value in having an IMyService interface explicitly because it simplified the specification/tests for the parts of the system that need to use it, and decoupled the system to a point that made it much easier to code and change.

So my question is, do you see any real value in a specification/test name like “When doing something, should do something”? or should I be looking at this test from a different “style” or perspective?

I think this specification/test is valuable, but I also think the test name and observation name are silly since they say the same thing. Advice? Different naming suggestions? What am I missing or just not seeing? or is this ok and I’m just running on 25% brain power due to lack of sleep today?



_________________________________
Cross Posted From LosTechies.com
Thursday, February 19, 2009 7:01:19 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Behavior Driven Development | C# | Unit Testing

 Thursday, February 05, 2009

I’ve written a lot of specification tests like this in the last three years, from a UI / Workflow perspective, with Model-View-Presenter as my core UI architecture:

[TestFixture]
public class When_starting_some_process()
{
 
 IMyView view;
 MyPresenter presenter;
 
 [Setup]
 public void Setup()
 {
   //...setup code and execute stuff for the test here
   view = MockRepository.GenerateMock<IMyView>();
   presenter = new MyPresenter(view);
 
   presenter.StartSomeProcess();
 } 
 
 [Test]
 public void Should_attach_the_view_to_the_presenter()
 {
   presenter.View.ShouldNotBeNull();
 }
 
 [Test]
 public void Should_show_something()
 {
   view.AssertWasCalled(v => v.ShowSomething(something));
 }
 
}

The Devil In These Details

I had one of those ‘aha!’ moments yesterday where several of my nagging suspicions and annoyances at writing specification tests like this example finally gelled into a coherent understanding. That understanding is easily stated by saying that the test, “Should_attach_the_view_to_the_presenter” is invalid and should never be written. There are a number of reasons for this.

  1. In practicing BDD, the technical jargon that is leaking into the test is irrelevant to the real value that is intended with this specification
  2. In practicing any form of TDD, the implementation detail of attaching a view to a presenter creates a brittle test – I care about the API and how the system really works, not a very technical, implementation detail like this.
  3. Exposing the “View” property of the Presenter object is a violation of encapsulation and an ‘over-intimate’ smell. My test has far too much fine detail, granular knowledge of what’s going on behind the scenes, to really be of any practical value
  4. Finally – and possibly outweighing all other reasons combined – it’s simply not necessary.

Look at the second test: “Should_show_something”. It’s actually using the view. Presumably, the “StartSomeProcess” method on the presenter is going to call a method on the view – that’s why we are asserting that the method on the view was called. If this is true, then it can be safely assumed that not having a view attached to the presenter would throw a null reference exception when trying to call that method on the view.

If not having the view attached to the presenter results in a null reference exception for the other test, then we have a valid reason for that test to fail. We certainly can’t say that the view’s method was called when the view is null. Therefore, testing to ensure that we have a view attached to the presenter is a duplication of effort. We’re only proving what we have already proved transitively, via another test.

Beauty And Meaning In Simplicity

Assuming that this is all true, we can remove that test entirely. Our specification now looks like this:

[TestFixture]
public class When_starting_some_process()
{
 
 IMyView view;
 MyPresenter presenter;
 
 [Setup]
 public void Setup()
 {
   //...setup code and execute stuff for the test here
   view = MockRepository.GenerateMock<IMyView>();
   presenter = new MyPresenter(view);
 
   presenter.StartSomeProcess();
 }
 
 [Test]
 public void Should_show_something()
 {
   view.AssertWasCalled(v => v.ShowSomething(something));
 }
 
}

It’s one less test to deal with, yet is as expressive and meaningful. In fact, I would say it is more meaningful because we have avoided all of the problems I listed. I’m reminded of a quote by Alan Cooper:

“No matter how beautiful, no matter how cool your interface, it would be better if there were less of it.”

Although I think he was specifically addressing User interfaces in this quote, it is applicable to all interfaces – programmatic, user, etc. Simplicity and subtleness is the key. I know I’m not the first person to talk about this problem, why it’s a problem, or the solution. I’m only claiming that I finally had that ‘aha!’ moment and realized why so many others have talked about this before.



_________________________________
Cross Posted From LostTechies.com
Thursday, February 05, 2009 5:16:48 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Analysis and Design | Behavior Driven Development | C# | Model-View-Presenter | Principles and Patterns | Unit Testing

 Wednesday, November 19, 2008

Finding Classes With Resharper

It's no secret that I'm a huge fan of Resharper. It rocks. I don't like to code without it. One of the many features that I love is the Ctl-N shortcut to find a class. Resharper gives you this handy-dandy little search box:

image

What I really love about this box is the ability to not know the entire class name when searching. If I know my class involves the word "Super" and "Sexy", I can type the letters "SS" and the search box will pull up any class with matching uppercase letters.

image

The same holds true for lowercase letters. I can do "SupSeV" and get results just matching those Upper/lower combinations.

BDD Context Specifications Have Long Strange Names

It's also no secret that I'm a fan of BDD and Context/Specifications. I love the language oriented nature of context specifications and how it's easy for me to see what the behavior of the system is supposed to be, in any given context. I've been using BDD style syntax for many months now, and have amassed quite a collection of Context/Specification tests in my current code - especially with 4 other developers using BDD syntax. After having done several hundred tests in this manner, I've found that there is a pretty significant disconnect between how I use SpecUnit.NET and how Resharper's class finder works - the names of my specification classes. Look at this specification class name for example:

image

How am I supposed to search for this class name? I can't remember all those words, none of them are capitalized, and all those underscores are probably going to throw Resharper off in my search string.

Organizing Context/Specification Classes By Parent Class/File Name

To combat this problem, what I've started doing recently is throwing in the use of a parent specification class with the same name as the specification file that I'm working in. Since our team has standardized on the "Specs" suffix for all of our BDD tests, I know that a file name of "ValidationSpecs.cs" will have a class called "ValidationSpecs". In the file itself, my specs will be subclasses, like this:

image

With the file name ValidationSpecs and the parent class ValidationSpecs, I now have much fewer words to remember and a much greater chance that I'll be able to use Resharper's class finder feature. All I need to know that I'm looking for the tests that deal with validation, so by our naming convention, I can type in "VS" or "ValSpecs" and get the list back that I want:

image



_________________________________
Cross Posted From LostTechies.com
Wednesday, November 19, 2008 5:56:35 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Agile | Behavior Driven Development | Continuous Integration | Resharper | Unit Testing

 Tuesday, October 07, 2008

A few months ago, I posted some thoughts and questions on the proper use of Inversion of Control (IoC) containers and the Dependency Inversion (DI) principle. Since then, I've had the opportunity to do some additional study and teaching of DI, and I've had that light bulb moment for the proper use of an IoC container. I haven't talked about it or tried to present the info to my team(s) yet, because I had not verified my thoughts were on the right track - until recently. I got to spend a few hours at the Dovetail office with Chad, Jeremy, Josh, etc, and had the pleasure of being able to pick their brains on some of the questions and thoughts that I've had around DI and IoC. In the end, Chad confirmed some of my current thoughts and helped me put into a metaphor that I find to be very useful in understanding what Dependency Inversion really is - a cloud objects that can be strung together into the necessary hierarchy, at runtime.

Consider a set of classes that need to be instantiated into the correct hierarchy so that we can get the functionality needed. It's really easy to have the highest level class - the one that we really want to call method on - instantiate the class for next level down, and have that class instantiate it's next level down, and so-on, like this:

image

This creates the necessary hierarchy, but breaks the core object oriented principle of loose coupling. We would not be able to use ThisClass without bringing ThatClass along with it, and we would not be able to use ThatClass without bringing AnotherClass along with it.

By introducing a better abstraction for each class and putting Dependency Inversion into play, we can break the spaghetti mess apart and introduce the ability to use any of these individual classes without requiring the specific implementation of the dependent class.

For starters, let's introduce an interface for ThisClass to depend on and an interface for ThatClass to depend on.

Adding Dependent Interfaces

Now that we have an interface that both of these classes can depend on, instead of the explicit implementation of the child object, we need to have the expected child object implement the interface in question. For example, we expect ThatClass to be used by ThisClass, so we will want ThatClass to implement the IDoSomething interface. By the same notion, we want AnotherClass to implement the IWhatever interface. This will allow us to provide AnotherClass as the dependency implementation for ThatClass. Our object model now looks like this:

Implementing Dependency Interfaces

What we have now is not just a set of classes that all depend on each other, but a "cloud" of objects with dependencies and interface implementations that will let us build the hierarchy we need, when we need it.

The Cloud Of Objects

The real beauty of this is that we no longer have to care about the implementation specifics of IDoSomething from ThisClass. ThisClass can focus entirely on doing it's duty and calling into IDoSomething when it needs to. And, by passing in the dependency as an abstraction, we're able to replace the dependency implementation at any time - runtime, unit test time, etc. This also makes our system much easier to learn and understand, and most importantly - easier to change.

Now that we have our cloud of implementations and abstractions in place, we will need to reconstruct the hierarchy that we want so we can call into ThisClass and have it perform it's operations. Here's where Dependency Inversion meets up with Inversion of Control.

  • To create ThisClass, we need an implementation of IDoSomething
  • ThatClass implements IDoSomething, so we'll instantiate it before ThisClass
  • ThatClass needs an instance of IWhatever
  • AnotherClass implements IWhatever, so we'll instantiate it before ThatClass
  • Once we have AnotherClass instantiated, we can pass it into ThatClass's constructor
  • Once we have ThatClass instantiated, we can pass it into ThisClass's constructor

We end up with a hierarchy of objects that is instantiated in reverse order, like this:

Reconstructing The Hierarchy Of Depdencies

We have now successfully inverted our system's construction - each implementation detail is created and passed into the the object that depends on it, re-creating our hierarchy from the bottom up. In the end, we have an instance of ThisClass that we can call into, with the same basic hierarchy of classes that we started with. The real difference is that now we can change this hierarchy at any time without worrying about breaking the functionality of the system.

Once we have our Dependency Inversion and Inversion of Control in place, we can start utilizing the existing IoC frameworks to automatically create our hierarchy of objects based on the advertised dependencies (an advertised dependency is a dependency that is specified as a constructor parameter of a class). Tools like StructureMap, Spring.net, Windsor, Ninject, and others, all provide automagic ways of creating each dependency of the object that is requested, all the way up/down the hierarchy. Utilizing one of these IoC containers can greatly simplify our code base and eliminate the many object instantiations that would start to liter our code. As I said in my previous post, I know all about what not to do with IoC containers. Good IoC usage, though, is another subject for another post.

Tuesday, October 07, 2008 9:18:31 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Analysis and Design | Design Patterns | Principles and Patterns | Refactoring | Unit Testing

 Monday, September 29, 2008

At some point, you will need to put a timer into your C# code. Hopefully you're doing Test Driven Development, or at least unit testing, to cover your need for a timer with a unit test. If you are - I'm betting you ran into some really ugly problems like tests that would not pass without having 'Thread.Sleep(1000)' calls in them. Worse yet - last week, I put a 3 second timer into a class that was being unit tested. This one mistake cause my CruiseControl build to go from 2 minutes, to timing out at 90 minutes because NUnit was keeping the app domain alive while the timer was alive, so it never closed the test run. Oops.

To fix this problem, we decided we needed to eliminate the use of an actual timer and use an abstraction that could be mocked/controlled in our unit tests. Unfortunately, the .NET Framework does not have an actual abstraction for a timer. So, if you need to use a timer in your code - and at some point in time, you will - you'll want to create a very simple ITimer interface that would let you control when the timer elapses and fires its registered action.

Here's the core of the abstraction that we came up with, initially.

public interface ITimer
{
    void Start(Action timerAction);
}

With such a simple interface in place, we can now mock it out in our unit tests (I like Rhino Mocks) and set up an expectation on the Start method to capture the timerAction parameter, then simulate the timer elapsing by calling the timer action from our unit test. Here's an example test and 'system under test' to illustrate how we use this interface.

[Test]
public void DemonstratingHowToUnitTestATimerElapsing()
{
    Action timerElaspedAction;
    ITimer timer = MockRepository.GenerateMock<ITimer>();
    timer.Expect(t => t.Start(null)).IgnoreArguments().Callback(
    delegate(Action timerAction)
    {
        timerElapsedAction = timerAction;
        return true;
    });
 
    MySystemUnderTest sut = new MySystemUnderTest();
    sut.StartMonitoringStuff(timer);
 
    //here's where we simulate the timer elapsing
    timerElapsedAction();
 
    Assert.IsTrue(sut.TheTimerActionWasCalled);
}
 
public class MySystemUnderTest()
{
    public bool TheTimerActionWasCalled { get; set; }
 
    public MySystemUnderTest()
    {
        TheTimerActionWasCalled = false;
    }
 
    public StartMonitoringStuff(ITimer timer)
    {
        timer.Start(() => TheTimerActionWasCalled = true);
    }
}
 

There is a bit more detail to the actual ITimer interface, and the implementation, though. We ran into issues where we needed to stop the timer, prevent it from firing after we close the SUT, etc. So, all said and done, here's the full ITimer interface and MyTimer implementation that we ended up with.

public interface ITimer
{
   void Start(Action action);
   void Stop();
}
 
public class MyTimer : ITimer, IDisposable
{
 
   private TimeSpan _timerInterval;
   private Timer _timer;
 
   private Action _timerAction;
 
   private bool IsRunning { get; set; }
 
   public MyTimer(TimeSpan timerInterval)
   {
       _timerInterval = timerInterval;
   }
 
   public void Dispose()
   {
       StopTimer();
   }
 
   public void Start(Action action)
   {
       _timerAction = action;
       IsRunning = true;
       StartTimer();
   }
 
   public void Stop()
   {
       IsRunning = false;
       StopTimer();
   }
 
   private void StartTimer()
   {
       _timer = new Timer(o => Timer_Execute(), null, 0, Convert.ToInt32(_timerInterval.TotalMilliseconds));
   }
 
   private void StopTimer()
   {
       if (_timer != null)
       {
           _timer.Change(Timeout.Infinite, Timeout.Infinite);
           _timer.Dispose();
           _timer = null;
       }
   }
 
   private void Timer_Execute()
   {
       try
       {
           StopTimer();
           _timerAction();
       }
       finally
       {
           if (IsRunning)
               StartTimer();
       }
   }
 
}

This has worked out very well for us, so far. It lets us put a timer in place when we need one, but not worry about thread racing issues, long running tests, etc.

Monday, September 29, 2008 7:38:33 PM (Central Standard Time, UTC-06:00)  #    Comments [2]. Trackback 
Tags: .NET | Lambda Expressions | NAnt | Rhino Mocks | Test Driven Development | Unit Testing

 Wednesday, September 10, 2008

After some additional Twitter discussion with Jimmy last night, I realized that my previous response had neglected to distinguish between two very important contexts - new code and legacy code.

Considering a legacy system (as defined by Michael Feathers), I'm 100% on board with everything Jimmy is talking about and all of the techniques, troubles, and diminishing returns that he identifies.

I still maintain that 100% coverage should be the default result of true TDD when writing new code - and I apply this philosophy when writing new code inside of a legacy system. Write a test to prove you need the new code that you are writing... unfortunately, the distinction between new and legacy code does get blurry and can be difficult to navigate when working in a legacy system.

For more info on legacy code, in this context, and how to deal with it:

Wednesday, September 10, 2008 7:25:17 AM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: Agile | Code Coverage | General | Management | Philosophy of Software | Principles and Patterns | Refactoring | Test Driven Development | Unit Testing

 Tuesday, September 09, 2008

I've talked about code coverage and software quality with a number of people on Twitter in the last month or so, including Jimmy Bogard, who has a nicely written post about Quality and code coverage.

It's no secret that I have some fairly radical opinions on code coverage and that I don't agree with Jimmy in these regards. I firmly believe that 100% code coverage, in whatever form we can get, is a reasonable goal and not past the point of diminishing returns. As such, I'd like to respond to some of what Jimmy is saying and expand on it with my own thoughts.

But first - I don't like to draw hard lines between "Unit" tests and "Integration" tests - that just blurs the problem even more because we can argue that you are covering code or not, in "unit" tests all day long, based on this blurry line. This is not the discussion I want to have, so I am lumping "Unit" and "Integration" tests into "Unit" tests as a whole.

Secondly, I'd like to say that code coverage is not always an indication of quality - in poorly written systems, it's merely a measure of code coverage. However, quality code is another subject of much debate.

On to the response!

.............................................

"The idea is that the team, all practicing TDD, should dutifully measure and add unit tests until they reach the assumed pinnacle of unit testing: 100% coverage."

There are several assumptions and statements in this that I don't believe are true.

For one, TDD and Unit Testing are not the same - no where near the same. Unit Testing lets you add tests as you see fit - after you write the code, while you write the code, whenever you want. You can even do test-first unit testing. True TDD, however, is a pure pragmatic approach to software development in that you never write code that does not have proof of need to exist - a test that says it needs to be there. 

The "pinnacle" of TDD and Unit Testing are not the same thing. Unit Testing - the act of adding unit tests when you see the need - may have a goal of 100% coverage. TDD, on the other hand, has a goal of only implementing the code that has been specified as needed. 100% coverage is the default in TDD because you never write code you don't need.

If you are going through the "measure and add unit tests" process, I would put money down to say that you are doing Unit Testing and very little TDD. The process should be something more like "measure to make sure we haven't added anything we don't need yet". 100% coverage is a side effect of TDD.

"The general motivation behind 100% coverage is that 100% coverage equals zero bugs."

Unfortunately, this is the motivation for many people who write unit tests - but it's the wrong motivation. You will never be 100% bug free just because you have 100% code coverage. There will always be some business case or external system factors that cause a bug now and then. That doesn't mean we should be ok with letting bugs into our system. On the contrary, one of our motivations (not the only one) should be to prevent as many bugs as possible from getting into the system.

"NCover is a powerful tool, but it still doesn't support all types of coverage.  Attaining 100% coverage in NCover still means there are paths that we haven't tested yet, which means there are still potential bugs in our code. "

I think the logical conclusion of this argument is that if we don't have a tool that supports true 100% coverage, then we shouldn't use that tool at all. I know I'm inserting my own conclusions into Jimmy's words - that's simply the conclusion that I came to from these statements. And this is a very bad conclusion. Do you walk around naked simply because wearing clothes would get them dirty and you'd have to wash them? Both of these are akin to the broken window syndrome. Use the tools that are available to the extent that they can operate, and find better tools when you can.

"If 100% coverage is a goal,"

100% coverage should NEVER be a goal - it's merely an indication that you are on the right path and working pragmatically.

"In recent projects where we measured coverage several months in to the project, we saw regular numbers of 90% coverage.  This was on a team doing 100% TDD." ... "So are we doing TDD wrong?"

So, are you doing TDD wrong? Yes. You are unit testing in the guise of Test-First-Development and not adhering to the spirit or pragmatism that TDD wants.

"Every test introduced covered behavior we considered interesting.  If behavior isn't interesting, we don't care about it. "

If you have code that is not interesting and you don't care about it - why is it in the system? If you don't care about the code, then it makes no difference whether or not that code works correctly. I would be appalled to hear that this is true. If it is true, then that code should not be in the system to begin with.

"If tests are a description of the behavior of the system, why fill it with all the boring, trivial parts?  The effort required to cover triviality is just too high compared to other ways we can increase value."

I think your definition of "behavior" is wrong. From wordnet.princeton.edu/perl/webwn:

Behavior: "the action or reaction of something (as a machine or substance) under specified circumstances;"

So, how is throwing an exception when a parameter is null, not behavior? If you are doing defensive programming to make sure you have all the data you need, then you are creating behavior - system behavior, not business process behavior. Behavior is still behavior, though. The only possibility of code not being behavior is a simple data point. If you have a data point in your code that is not covered by a unit test of behavior, then you don't need that data point. Yes, yes, I know - "integration", "nhibernate", "not my data source", "it has to be there for ...". If you argue that you need a property for some external portion of the system to operate correctly, then you should be proving that you need the property by covering it with a unit test that specifically says what it is for and shows how it is used. If you don't, then there's no way of knowing why the property exists and it may be deleted because it looks like nothing in the system uses it. Or, possibly worse, you end up with a lot of dead code in your system because you are afraid of deleting anything.

"Missing in the 100% coverage conversation is the effort required to get to 100%.  Attempting to get another 5% takes equal effort of the previous 10%.  The next 2% takes equal effort of the previous 15%, and so on."

I'd like to know where you got the math. If you are talking about unit testing - even test-first unit testing - i can understand the pain you're talking about, here. Why should I bother setting up another test fixture and getting all the state of my objects in place for a simple null reference check? blech - that totally sucks, is boring, is tedious, etc.

However, my typical process of achieving 100% is to only write code that is needed for the system to work, by specifying how the system will work through tests and then coding it. If I have a null reference check somewhere in my code it should be because I already have a test that specifies why it's needed.

"This is called the law of diminishing returns.  As we get closer and closer to 100%, it takes vastly more effort to get there.  At some point, you have to ask yourselves, is there value in this effort? "

Here's the real crux of the problem - you are assuming that you started with, or at some point has less than 100% coverage. It takes zero additional effort to stay at 100% coverage if you start at 100% coverage and maintain it through pragmatic TDD.

"Often, bending code to get 100% can decrease design quality, as you're now twisting the original intent solely for coverage concerns, not usability, readability or other concerns."

If you find yourself bending code to get 100% coverage, you have one of two situations (if not both): 1) poor design in your code, 2) poorly written tests. I would bet that you have both because they are a vicious circle.

"Measuring coverage is an interesting data point, as are other measures such as static analysis.  But in the end, it's only a measure, an indication. "

100% agreed!

"It's still up to the team to decide on the value of addressing missing areas,"

This implies that you don't have 100% coverage, already. In this situation, 100% agreed. I'm in this situation right now - it's hard to know what tests create the most value, at this point. However, any new code - even code changes to existing code - are done TDD style. So, while we don't yet have 100% coverage, we are increasing coverage all the time by never writing code without a test (that's part of the goal, anyway... no one is perfect, and it takes serious discipline to do this)

"with the full knowledge that they are still limited to what the tool measures."

Agreed, again. If you don't know the limitations of the tools you are using, you're in trouble.

.............................................

The boilerplate argument that I am making is that you should never write code that is not required by a customer / consumer. However, as I've Previously Talked About, there's a high likelihood that you have not identified all of your customers / consumers. Take NHibernate, for example. I have a project that needs about 30 different properties for a specific NHibernate query to be executed. The NHibernate query is the only place they are ever used - no code reads them, only a search screen writes to them, then the NHibernate query loads data from the table that they are mapped to. When I first wrote this code, my coverage was at around 30%. This situation is one of many that I've been in recently, that has lead me to believe that other code must be considered a customer / consumer of your code. If I deleted any of these properties, then the NHibernate query would fail. Therefore, the properties are valuable to NHiberate. Since these properties are valuable to at least one of the consumers of my code, I should prove that they need to exist by writing a test that proves they are needed and why.

Tuesday, September 09, 2008 12:39:11 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: Code Coverage | General | Lean Systems | Management | Philosophy of Software | Principles and Patterns | Refactoring | Test Driven Development | Unit Testing

 Monday, July 21, 2008

Test Driven Development Is To Unit Testing As Interaction Design (IxD) Is To Accidental Design

One of the major problems with writing unit tests after the code is that it is very natural to write tests that prove the code works the way it was written, instead of the way it should work. Writing code test-first (via whatever flavor of Test Driven Development) flips that scenario right side up. TDD helps to ensure that code is written to work according to specifications and not the other way around.

Similarly, designing and/or implementing a UI after a behavior or process has been coded is a likely to result in a UI that fits the code model and not a model that fits the needed interaction and workflow. This situation must also be flipped right side up - interaction design should be done before, or at least in parallel, with coding. It cannot be left to accidental or incidental happenstance - interaction design must occur with proper interaction patterns and practices in mind.

Overlapping IxD and TDD

To overlap interaction design and test driven development, there are a few key words that need to be borrowed from interaction design. Fortunately, they easily fit within TDD development techniques and philosophies.

Epistemic work is exploratory in nature, or a process of trial and error through research. TDD and interaction design sketching are both epistemic. TDD explores API possibilities and allows easy trial and error to find the simplest implementation for what you need at the time. UI design sketches also allow you to quickly explore interaction designs - whether it's a white board, pencil and paper, graphics design software, or even quick-hack forms layout in IDEs. You can quickly and easily throw away a bad API in TDD and you can quickly and easily throw away a bad UI/Interaction design when you have nothing more than pencil sketches or white board drawings.

Pragmatic work is very structured and step-by-step in it's nature, implementing patterns and practices to fulfill what is needed at the moment. Implementing Code after writing unit test and implementing UI after designing around constraints are both pragmatic. TDD is pragmatic in that you only implement what is needed to properly pass the tests that have already been written. Similarly, with previously designed interactions and UI elements, implementation can be easily limited to what is needed for the UI.

With epistemic and pragmatic work covering both interaction design and test driven development, it seems that they are a natural pair. An analysis of a user story and it's acceptance criteria will create the unit tests that we need. At the same time, the same analysis can be applied to interaction designs. Additionally, a strong understanding of how a UI will look can have a profound impact on the code that is written, and vice-versa. Therefore, it is natural that interaction design and test driven development are done at just-in-time intervals - before the real work is implemented in the real code and UI platform.

IxD As Part of "Done"

Despite interaction design being a required part of UI development, not all user stories require a UI. Interaction design may not fit into a swim lane board or be part of every story's "done" criteria. However, interaction design will always be done for any story that does have a UI - it may simply be an accidental or incidental part of the software development process for a team, though. If it's safe to assume that the work will be done, then it is the team's responsibility to ensure that it is done correctly. Don't let interaction design happen accidentally or incidentally in the development process. Set a standard of always including interaction design in the development process, the same way Model View Presenter/Controller is a part of development.

Monday, July 21, 2008 8:47:04 AM (Central Standard Time, UTC-06:00)  #    Comments [3]. Trackback 
Tags: Agile | Analysis and Design | Behavior Driven Development | Interaction Design | Management | Model-View-Presenter | Principles and Patterns | Test Driven Development | Unit Testing | User Stories

 Tuesday, July 15, 2008

In the last month or two, I have been hand coding a lot of mock and stub objects and it has become a nightmare to manage. My primary reason for doing this by hand was that Rhino Mocks 3.4 and older did not fit with the BDD style unit tests that I was writing. Yes, I made it work in a few places, but it was ugly and annoying.

Fortunately, Ayende has cleaned it all up with the new syntax and made it very easy to assert that individual expectations were met, with v3.5. I finally got around to trying out the new syntax today, and I immediately fell in love with it. For example:

[Concern("User Administration")]
public class When_accessing_the_system_as_a_non_administrator : ContextSpecification
{
    private IMainView view;
 
    private IMainView GetView()
    {
        IMainView mockView = MockRepository.GenerateMock<IMainView>();
        mockView.Expect(v => v.EnableUserManagement()).Repeat.Never();
        mockView.Expect(v => v.DisableUserManagement()).Repeat.Once();
        return mockView;
    }
 
    protected override void Context()
    {
        User administrator = new User();
        administrator.IsAdministrator = false;
        CurrentUser.User = administrator;
 
        view = GetView();
        new MainPresenter(view);
    }
 
    [Observation]
    public void Should_not_display_the_User_Management_option()
    {
        view.AssertWasNotCalled(v => v.EnableUserManagement());
    }
 
    [Observation]
    public void Should_hide_the_user_management_option()
    {
        view.AssertWasCalled(v => v.DisableUserManagement());
    }
 
}

In the "GetView" method, I am setting up two very distinct expectations on my mock object.

  1. Never Call the EnableUserManagement method.
  2. Call the DisableUserManagement method once.

With the new Rhino Mocks syntax, I can easily verify that each one of these expectations was called via my "should" observations.

The "AssertWasNotCalled" extension method verifies that an expectation of Repeat.Never was setup and that the method was not called.

mockView.AssertWasNotCalled(v => v.EnableUserManagement());

And the "AssertWasCalled" extension method verifies that the expectation was to call the method, and that the method actually was called.

mockView.AssertWasCalled(v => v.DisableUserManagement());

I like it. The new syntax has really simplified my Context Specification testing.

Tuesday, July 15, 2008 2:43:10 PM (Central Standard Time, UTC-06:00)  #    Comments [1]. Trackback 
Tags: .NET | Behavior Driven Development | Lambda Expressions | Rhino Mocks | Unit Testing | User Stories

 Thursday, June 19, 2008

Inspired by my recent readings in Domain Driven Design - specifically Chapter 10, "Supple Design" - and recent posts by David Laribee and Nigel Sampson, in combination with the recent pains I've been putting myself through, trying to test query generation code in a search screen, I decided to spike out a quick example of a reusable Specification implementation.

Rather than repeat what's already been said, I'm just going to get straight to the code.

using System;
 
namespace Spec_Spike
{
    class Program
    {
        static void Main()
        {
        
            Foo foo1 = new Foo();
            foo1.Bar = "Test";
            
            ISpecification<Foo> equalSpec = new Specification<Foo>(foo => foo.Bar == "Test");
            ISpecification<Foo> notEqualSpec = new Specification<Foo>(foo => foo.Bar != "Not Equal To This Text");
            ISpecification<Foo> falseSpec = new Specification<Foo>(foo => false);
 
            ISpecification<Foo> passingSpec = equalSpec.And(notEqualSpec);
            ISpecification<Foo> failingSpec = passingSpec.And(falseSpec);
 
            Console.WriteLine(equalSpec.IsSatisfiedBy(foo1));
            Console.WriteLine(notEqualSpec.IsSatisfiedBy(foo1));
            Console.WriteLine(passingSpec.IsSatisfiedBy(foo1));
            Console.WriteLine(failingSpec.IsSatisfiedBy(foo1));
        }
        
    }
    
    public class Foo
    {
        public string Bar;
    }
    
    
    public interface ISpecification<t>
    {
        bool IsSatisfiedBy(t obj);
        ISpecification<t> And(ISpecification<t> lhs);
    }
    
    public class Specification<t>: ISpecification<t>
    {
        private readonly Predicate<t> _pred;
 
        public Specification(Predicate<t> pred)
        {
            _pred = pred;
        }
 
        protected Specification(){}
    
        public virtual bool IsSatisfiedBy(t obj)
        {
            return _pred(obj);
        }
 
        public ISpecification<t> And(ISpecification<t> andSpec)
        {
            return new AndSpecification<t>(this, andSpec);
        }
    }
    
    public class AndSpecification<t>: Specification<t>
    {
        private readonly ISpecification<t> _spec1;
        private readonly ISpecification<t> _spec;
 
        public AndSpecification(ISpecification<t> spec1, ISpecification<t> spec)
        {
            _spec1 = spec1;
            _spec = spec;
        }
 
        public override bool IsSatisfiedBy(t obj)
        {
            return (_spec.IsSatisfiedBy(obj) && _spec1.IsSatisfiedBy(obj));
        }
 
    }
    
}

Drop this code into a console app in C# 3.5 and watch the magic happen. Here's the output:

image

These are the results that I expected - the first 2 individual specs passed, the first combined spec passed, and the last combined spec failed.

Overall, I'm fairly excited about the possibilities here. I'm thinking that I may actually be able to properly unit test the query generating code in my search screen with this basic technique. I'm still not 100% sure on that, but I plan on trying, anyway.

For more information on the Specification pattern, I highly recommend you read the previously linked posts by David Laribee and Nigel Sampson, in addition to reading all of the Domain Driven Design Book. This is one of those books that should fundamentally change the way you think about software development.

Thursday, June 19, 2008 8:35:20 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Analysis and Design | Design Patterns | Domain Driven Design | Lambda Expressions | Principles and Patterns | Unit Testing

 Friday, May 09, 2008

The Toyota Way mentions the concept of Jidoka in chapter 1 (and probably other places that I haven't read yet). On page 6, in the "4 P" diagram, jidoka is described as

"Stop when there is a quality problem"

Wikipedia calls the same concept "Autonomation" and says it may be described as

"intelligent automation" or "automation with a human touch"

and

"At Toyota this usually means that if an abnormal situation arises the machine stops and the worker will stop the production line."

We can apply the same principles in software development in many different ways. One of the more common implementations is the use of Continuous Integration and Automated Testing.

According to the notes I took during A Day Of Bellware, if our CI server says the build is broken, we need to immediately stop working and fix the problem. I've heard this before, and will likely hear it again. However, I never really understood why people would say this. After all, as long as the problem is fixed eventually, isn't that ok? In the training that day, Scott provided a excellent visualization of why we should fix it immediately.

Waste and Rework

To steal Scott's illustrations, consider the following image to be an example of "perfect" software. All of the edges of each module (block) are well defined and it's easy stack new blocks next to existing blocks.

Figure 1. "Perfect" software

image

Now let's assume that somehwere in the coding process, someone accidentally causes a defect in the software. That defect could be represented by a buldge in one of the lines - as if the module was doing more than it should.

Figure 2. A defect

image

The individual block that has the defect may not be that bad, at first glance - or when examined on it's own. And on it's own, the defect could be fixed. Jidoka would say that you need to stop immediately and fix the problem.

So, what happens when you don't fix the problem right and and you try to stack another block to the right of the defect? Suddenly you find yourself re-shaping the next block in order to account for the problems in the previous one. Eventually, you may be able to smooth out the issues. Depending on the size of the issue, though, it may take several new modules to completely normalize things.

Figure 3. The effect of a defect

image

Now, 3 day, 3 weeks, 3 months, or whatever period of time later, you have a significantly larger problem to deal with. Let's go back and fix the original cause of the problem, to start with. What happens to the rest of the code that was warped around the original defect? The warped code in the rest of the system also has to be fixed. Simply removing the original bulge does not mean that the rest of the warps will magically disappear as well.

Figure 4. Removing the original bulge

image

How much re-work will it take to fix the rest of the system that was warped around the original problem? How much time and effort will be wasted because the original defect was not addressed immediately? These questions can only be answered in the context of your problems. If this defect is one line of code in one module, maybe it's not so bad. But if this defect is an entire module used by many other modules, the time and cost could be huge.

Conclusion: Fix It Now

If the continuous integration server says that our build is broken; or if the customer says "the software does not break, but piece XYZ isn't correct"; or ... pick a problem in your system; we need to respond as quickly as possible, in order to prevent the rest of the system from being warped by the original problem.

Under the assumption that we want to fix a defect as soon as possible - how do we ensure that we know about the problem as soon as possible? Whatever your implementation of this solution is, the solution to this problem comes down to shortening the feedback loop. If you are notified of the problem in 20 minutes vs. 20 days, there will be significantly less damage to the overall system and significantly less re-work and waste caused by the defect.

Friday, May 09, 2008 2:53:12 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: Acceptance Testing | Agile | Lean Systems | Principles and Patterns | Unit Testing

 Wednesday, May 07, 2008

Myself and 10 other developers in my company went through a day of BDD / TDD training, with Scott Bellware, yesterday. It was a lot of fun, very challenging at times, and covered a lot of topics including an overview of Agile and Behavior Driven Development, all the way down to writing Specification Tests, doing Test Driven Development  and refactoring the model to improve readability, maintainability, flexibility, etc. I took notes via index cards (love that cool-aid) and wanted to share. I don't expect these notes to make sense to everyone. Hopefully it will spark some dialog in someone's mind and cause them to dig further.

First off - the quote of the day.

"Can I be honest with you and say that I've been wanting to touch your keyboard, all day?"

Now for my notes.

User Stories

[Role], [Goal], [Motiviation]

  • As a [role], I want to [goal], so that [motivation]
  • Example: As a nurse, I want to record a patients vital signs, so that I can determine their medication and care needs
  • Motivation is critical - it determines how the development team understands and implements the story. It determines the user experience, how things are integrated, how the software is designed, etc.

Acceptance Criteria

  • Acceptance Criteria is used to drive code, not the story, directly
  • may change at any point, up to implementation
  • is used to drive code design, test design, implementations, etc.
  • should be spoken in domain language
  • may include non-functional, technical details such as database tables, infrastructure, performance, etc
  • All acceptance criteria must be met and tested / verified before a story is considered done

Specification Tests

  • Test Fixture per Class is an anti-pattern (on a personal note, this problem bothered me for months before I discovered BDD)
  • Context Specification or Behavior Specification testing
  • When [verb] then [verb]
    • "When [verb]" is the context
    • "Then [verb]" is an observation of the behavior
  • Based on Acceptance Criteria, but not "code-gen'd" from acceptance criteria

Story Estimation

  • Agile Poker: uses generalized Fibonacci sequence as order of complexity
    • "?", 0, 1/2, 1, 2, 3, 5, 8, 13, 20, 40, 100, infinite
  • everyone throws their estimate at same time
  • if estimates have significant outliers, discussion occurs to understand why, get more detail, etc. and re-throw may happen

Entity Data vs. Aggregate Data

  • Entities should never contain aggregate data
  • Aggregate data is for reporting and other aggregate needs
  • If you need aggregate data to process something, write an SQL query, stored proc, etc. - don't use an ORM like NHibernate
  • We don't want a "Customer" entity to need 10,000 "Order" entities, to aggregate data for processing; write a query to aggregate instead
  • We don't want to persist data that can be calculated / aggregated, generally (performance issues may override this)

Domain Services

  • Can have dependencies on external systems
  • are part of domain logic, therefore are in domain model / assembly
  • are "Doers" of process that don't fit into entity and entity logic, directly
  • coordination of entity logic
  • can include calls to data access, logging, etc.

Continuous Integration

  • Not just continuous compilation of code
  • Full end to end integration of all code, components, databases, services, etc
  • Full suite of integration testing including database testing
  • Do not allow commits if build is currently broken
  • do not allow defects to live - fix immediately, to fix build
  • "Defect" is broken software, "Bug" is functional but wrong

Daily Scrum

  • 3 Questions everyone answers:
    • What did I do yesterday?
    • What am I doing today?
    • What issues am I having?
  • Each person should answer quickly - 1 or 2 minutes, max
  • further discussion happens outside of the Scrum meeting

Productivity of Dev Team

  • RAD and other non-review, non-iterative based management causes problems and loss of productivity
  • we need constant review of the design to ensure good design
  • shorten the feedback loop and get constant review of the design, to always improve the design, via pair programming, work cells, retrospectives, etc.
  • good design will cause productivity gains in the development team beyond the capabilities of any tools

Whiteboard Diagramming vs. Details Specs

  • White board diagramming and human interaction is always better than detailed documents and specs in UML
  • Human interaction leads to knowledge crunching and learning, not just reading a repeating
  • Take pictures, don't re-draw in UML; don't waste time with it
  • Video the entire conversation is even better, so others can learn from the knowledge crunching that occurs; capture the human interaction, body language, etc.
Wednesday, May 07, 2008 9:46:28 AM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Acceptance Testing | Agile | Behavior Driven Development | Data Access | Domain Driven Design | Lean Systems | Pair+1 Programming | Principles and Patterns | Refactoring | Test Driven Development | Unit Testing | User Stories

 Wednesday, April 30, 2008

I'm reading "Lean Software Development: An Agile Toolkit", and the first paragraph under "Tool 11: Queuing Theory" talks about the bottleneck that often occurs in the test lab - not enough testers, too much work for the number of testers, etc.

"We have often heard the lament 'My biggest problem is the testing department.' Now, testing people are very nice people: dedicated, hard working, and very important to the development effort. But there never seems to be enough of them to go around. And although the developers might write their own unit tests, testers frequently do acceptance testing. So, without enough testers, the whole development process bogs down."

The rest of the chapter talks about the queuing theory that can be applied to help alleviate the issue. It's a great chapter with lots of good information. I have a problem with the idea of applying this type of queuing theory to the the test lab, as a bottleneck, though.

First, let me state some assumptions about the primary responsibility of the testers in the test lab:

  • Testers are writing automated acceptance tests, for automated regression testing and integration testing
  • Testers are also doing human interaction testing, for the "human touch" of usability, etc.

If the testers are the bottleneck, and the two primary functions of the testers are as I have listed, then I think the there is a much more simple solution to the problem, from a lean perspective:

let the developers write the automated acceptance tests.

Assuming that the developers are already writing unit tests, and are therefore capable of writing code to test code, it makes a lot of sense in my mind that the developers should be writing the majority of the automated acceptance tests. It all goes back to the idea of flow - ensuring that the entire system (or process) has a smooth flow from beginning to end. This means that we may need to sub-optimize one area for the benefit of the whole, but the end result is that we will have a better system or process by making the entire flow as smooth as possible.

Counteracting Mura - or "Let's make it smooooooth"

If we are looking at the test lab as a bottleneck - a rough spot in the flow of our software development cycles - then let's take the most simple course of action possible, to reduce that rough spot as much as possible. Rather than spending so much time and effort on queuing theory and implementation, let's find a way to remove the bottleneck.

Assume that the software developers are experts at writing code - and writing code to test their code. Doesn't it make sense, then, that the software developers should be writing the acceptance tests, even if the acceptance tests are being specified by the customer and test lab personnel? If we allow the developers to take a little more responsibility, we may be sub-optimizing the development department a little. But, by doing so we are freeing up the much more scarce resources of the test lab and we can then make adjustments to the test lab's queue and workload, if needed. The idea of leveling out the flow of the system like this can be traced back to the Japanese term, Mura. The Wikipedia entry says it all:

"The fact that there is one operator will force a smoothness across the operations because the workpiece flows with the operator."

In this case, we are calling the combination of production code, unit tests and acceptance tests, the "workpiece". I believe this is a fair assesment, since the code and tests are all going to be based on a feature, use case, or user story. In fact, I would say that the workpeice actually is the feature, use case or user story that is being worked on. The code, unit tests and acceptance tests could be considered the artifacts products by the workpeice flowing through the system. ... but that's just splitting hairs, really.

It's all about Occam's razor, Parsimony, KISS, or whatever you want to call it - the simple solution is often the correct solution (simple, however, doesn't always mean easy).

The Need for the Test Lab

I'm certainly not saying we don't need a test lab. The testers are (supposed to be) experts in interaction testing, usability testing, and adding that "human touch". We absolutely need that perspective on those aspects of software testing that can't reasonably be automated. I am advocating that we find a better way to smooth the flow of the system - rather than apply complex theories and equations to the situation, find a solution that doesn't require anything complex.

Conclusions

In the end, the problem of the test lab bottleneck can be solved many different ways. You might level the system via Pair +1 Programming or some other form of involving the developers in writing the automated acceptance tests. Perhaps you make the testers part of the team and have them writing the automated tests at the same time as the developers writing code. You might still need to employ queuing theory. Either way, try to find the solution that works best to smooth out the process for your team.

Wednesday, April 30, 2008 2:22:44 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: Acceptance Testing | Agile | Behavior Driven Development | Management | Pair+1 Programming | Test Driven Development | Unit Testing

 Wednesday, April 23, 2008

Based on the proposed information and syntax from My Previous Post, I've created a basic Design By Contract unit testing framework. The intent of the code so far, is to provide a quick-and-dirty proof of concept. With that in mind, I give you

DBCUnit hosted on GoogleCode

You can get the source code via Subversion:

http://dbcunit.googlecode.com/svn/trunk/ 

Please note that the existing code only supports one assertion so far: Equals. Also, the execution engine is entirely made up of terrible code that assumes a lot of perfect-scenario input. I'm planning to flesh it out more and make the code more sustainable - actually adding Contract specifications for my execution engine, etc. Let me know what you think of the idea and the syntax. Also feel free to join the project and pitch in for syntax and implementation.

The one Contract I have specified so far, just to get rolling, is that a [PreCondition] should be executed once.

[Condition]
public class WhenPreConditionIsPresentInContractCondition
{
 
    private int preConditionExecutionCount = 0;
 
    [PreCondition]
    public void PreCondition()
    {
        preConditionExecutionCount += 1;
    }
 
    [PostCondition]
    public void ThePreConditionIsExecutedOnlyOnce()
    {
        Assert.That(preConditionExecutionCount).Equals(1);
    }
 
}

To run the test, run build the solution and run the DBCUnit.Console pointing to the DBCUnit.Contracts.dll, like this:

C:\...\> DBCUnit.Console.exe DBCUnit.Contracts.dll

If the test succeeds, there is currently no message printed to the console window. If it fails, it will write out a message saying what value it expected and what the value was. It's all very simplistic at this point, just a proof of concept. I also set up the DBCUnit.Console project to automatically start with the "DBCUnit.Contracts.dll" as the startup parameter, so you can step into the code via debugger and see it in action.

Have fun, and don't laugh too much. This is my first attempt at hacking together a unit testing framework.

Wednesday, April 23, 2008 7:50:08 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: Agile | DBCUnit | Design By Contract | Test Driven Development | Unit Testing

There's a lot of talk about Design By Contract (DBC) out there in the development world. Various development languages have varying support for it, but more importantly various processes have various levels of support for it.

It seems, though, that the farther down the path of development we travel, the more important it is for us to consider DBC in the code that we write. Large projects with multiple developers are in great need of DBC. Projects that have publicly distributed API's are in even greater need of DBC. Even if you are working on a simple, one person project for yourself, and you are the only one that will ever use it's methods and objects, I'm willing to bet that you will forget about the assumptions that you are making when writing the methods and objects, at some point.

So where does this distinct need for DBC leave us, in the world of .NET (C#, VB, and the other "common" .NET languages)? We still need a way to enforce DBC, but our language of choice doesn't support it, natively. So we have two real choices (excluding DSL writing, and/or switching languages) - documentation (via code comments or written / published documentation) or Unit Tests.

Yes, that's right - Unit Tests are not just for testing, anymore. Or more correctly, the tests executed by unit testing are not just for the sake of testing. The intention is verify the pre and post conditions of a design-by-contract. Of course, I'm not the first one to suggest this. It's mentioned briefly in "Agile Principles, Patterns, and Practices in C#" by Robert C. Martin and countless other times as well.

I am propose a new unit testing framework. I know, I know... "not ANOTHER xUnit framework... *sigh* ". In this case, I am proposing a semantic change along with the mechanical (syntax) change, specifically for the purpose of introducing unit testing to a group of developers that may not believe in "Unit Testing".

As an example of my proposed syntax, in a file called "SomeContract.cs", this test code would exist:

[Conditional]
public class WhenSomeConditionIsMet
{
    
    SomeValue someValue;
 
    [PreCondition]
    public void PreCondition()
    {
        Setup.My.Inputs inputs = Here;
    }
 
    [Execution]
    public void Execution()
    {
        someValue = Execute.TheContract.With(inputs);
    }
 
 
    [PostCondition]
    public void ThenSomeOutputIsSomeValue()
    {
        Assert.That(someValue).Equals("Some Known Value");
    }
 
 
    [PostCondition]
    public void ThenSomeOutputIsSomeValue()
    {
        Assert.That(someValue).DoesNotEqual("Some Unknown Value");
    }
 
}

To make this proposed syntax easier to understand, I'm basing it on the NUnit style of using attributes, at the moment; but it doesn't have to be that way. There is almost a one to one translation between NUnit and this.

  1. The [Conditional] attribute is equivalent to [TestFixture]
  2. The [PreCondition] attribute is equivalent to [TestFixtureSetup]
  3. The [Execution] attribute is equivalent to [Setup]
  4. The [PostCondition] attribute is equivalent to [Test]

In this simple example, I don't have an equivalent to [Teardown] or [TestFixtureTearDown]. I'm sure I'll need those at some point, but until I see the need, I'm not going to worry about them. I also don't really care about the Assert syntax. I'm just putting that syntax in place to illustrate the point.

Where I differ from typical NUnit style of testing is that I want to see a single "PreCondition" and "Execution" per test fixture, and have multiple "PostConditions" that only contain the assert statements. This style of test code more closely resembles that of Scott Bellware's SpecUnit.NET and for good reason - I like it. I'm a fan of having as little as possible in the method that does the assert - keep it simple and explicit.

The biggest problem I have with my proposed syntax is a problem inherent to Design By Contract - the idea that you know the object (contract) being executed. A huge part of why I love Behavior/Specification Testing vs. Unit Testing is that Unit Tests and TestFixtures typically tell you that for class/file "XYZ.cs" you have "TestFixtureXYZ.cs". Whereas, Behavior/Specification Testing says that we have "BehaviorSpecification.cs" regardless of the classes used to implement it. I love this about Behavior Driven Development - it freed my mind from the horrible constraints that I saw in standard Unit Testing / TestFixtures. Unfortunately, Design By Contract basically takes us right back to the same place. We are specifying contract (class) "XYZ" so we have a "XYZContract.cs" file to hold all of our [Conditional]s.

...

Does anyone else see any value in this style of unit testing? I can certainly see scenarios where this would appeal to some developers more than the standard xUnit frameworks.

Wednesday, April 23, 2008 12:48:39 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Agile | Design By Contract | Test Driven Development | Unit Testing

 Monday, March 31, 2008

A while back, I posted a stream of thoughts concerning programming in triples. The basic idea is that we have 2 developers doing pair programming and a third developer doing automated acceptance test development, on the same story at the same time.

Triples Programming Terms

I've been discussing this idea with various people since then, and I'm finding myself referring to this team organization with a specific term, now:

Pair+1 Programming

I don't know if this term has been used previously, or if there is already a term for this. However, I find this to be a good name for the organization that I am talking about.  It really is pair programming, as defined by many common sources, plus one acceptance test developer. The really fun part is that all three of the developers in this unit will switch roles throughout the day. The end result is that we have a very well cross-trained team - each member of each unit will be responsible for writing unit tests, writing production code, writing acceptance tests, and thinking ahead of the current code, throughout any given day.

An Agile Team includes more than just the developers - the customers, the test lead, the technical writers, the project manager, etc., are all part of the team. Pair+1 Programming is not into teams. A "team" implies that they the persons involved are fairly static - they don't move between teams, etc. In order to distinguish the Pair+1 organization from the Team as a whole, I am also going to refer to this group with another name:

Development Unit (Update: based on further discussion, renaming this)

WorkCell

Just as a developer will rotate rolls within the Unit, I believe Pair+1 programmers should move between WorkCells on a regular basis. This will further the cross-training that occurs and help to pollinate the knowledge of one WorkCell into the thoughts and goals of other WorkCells. The migration is likely to be less volatile than the role switching that happens within a WorkCell. For example, developers rotate positions every 2 or 3 hours, within the WorkCell, whereas a developer may only rotate between WorkCells once a day or once a week.

Development Systems

Within each Development Unit, there will be two development systems.

  1. The primary system of that Unit will be the pair programming system. This system should have a very large monitor - 30" is preferable - to allow the Pair to easy see everything on the screen.
  2. The secondary system will be used for Acceptance Tests and is likely to only need a 22" or 24" monitor, as it will be primarily used by a single developer.

Each of these systems, aside from monitor size, should be a mirror of each other - the same system specs with the same software development packages installed. Every machine used for development should be able to execute any of the tests - unit tests or acceptance tests - no matter the primary use of that development machine. This is required so that the Pair working on the Development machine can execute the Acceptance Tests being created on the Acceptance Test machine; thus ensuring that they are coding appropriately, and passing the expected tests. The Acceptance Test developer should also be able to execute the code being written by the Pair, to ensure that the Acceptance Tests are being written against the API correctly.

Following standard Agile practices, these machines should not be concerned with Email, IM, or other non-development tasks. They should be dedicated entirely to development work. If a person needs Email, IM, etc. then the office space should provide access via shared systems and/or a developer should have their own system (likely a laptop) that they can take with them wherever they go. The point is, though, to remove distraction from the Development Unit. Keep the non-development software off the Unit's systems, as much as possible, to ensure that the Unit can focus on development and not be distracted by 50 different flashing icons and windows on the machine.

Disclaimer

A lot of my thoughts are purely academic, at this point. I am hopefully going to have some actual experience with this environment, soon. As such, I am trying to organize my thoughts so that I can have some direction to start with. I reserve the right to be wrong and change my mind whenever I want, likely re-defining the terms and processes involved in Pair+1 Programming.

Monday, March 31, 2008 2:26:19 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: Acceptance Testing | Agile | Behavior Driven Development | Management | Pair+1 Programming | Unit Testing

In my previous post, I talked about my base repository class that I use, to abstract the NHibernate details away from the actual repository. Now that I have the Do and DoTransaction methods to further the abstraction, I thought it would be good to share my whole abstraction.

using System;
using NHibernate;
using NHibernate.Cfg;
 
namespace RepositoryBase
{
 
    public abstract class Repository : IDisposable
    {
 
        #region Vars
 
        private static readonly Configuration _config;
 
        private static readonly ISessionFactory _factory;
 
        #endregion
 
        #region Constructor / Destructor
 
        static BaseDAL()
        {
            _config = new Configuration();
            _config.Configure(typeof(BaseDAL).Assembly, "RepositoryBase.hibernate.cfg.xml");
            _factory = _config.BuildSessionFactory();
        }
 
        ~BaseDAL()
        {
            Dispose();
        }
 
        #endregion
 
        #region Properties
 
        public ISession Session { get; private set; }
 
        public ITransaction Transaction { get; private set; }
 
        #endregion
 
        #region Methods
 
        protected void Do(Action unitOfWork)
        {
            try
            {
                OpenSession();
                unitOfWork();
            }
            finally
            {
                CloseSession();
            }
        }
 
        protected void DoTransaction(Action unitOfWork)
        {
            try
            {
                OpenSession();
                BeginTransaction();
                
                if (unitOfWork != null)
                    unitOfWork();
                
                CommitTransaction();
            }
            catch
            {
                RollbackTransaction();
                throw;
            }
            finally
            {
                CloseSession();
            }
        }
 
        #endregion
 
        #region Helper Methods
 
        private void OpenSession()
        {
            if (Session != null) return;
 
            Session = _factory.OpenSession();
            Session.FlushMode = FlushMode.Auto;
        }
 
        private void CloseSession()
        {
            if (Session == null) return;
 
            if (Session.IsOpen)
            {
                Session.Close();
            }
            Session.Dispose();
            Session = null;
        }
 
        private void BeginTransaction()
        {
            ValidateSession();
 
            Transaction = Session.BeginTransaction();
        }
 
        private void CommitTransaction()
        {
            ValidateSession();
 
            if (Transaction != null)
                Transaction.Commit();
 
            CloseTransaction();
        }
 
        private void RollbackTransaction()
        {
            if (Transaction != null)
                Transaction.Rollback();
 
            CloseTransaction();
        }
 
        private void ValidateSession()
        {
            if (Session == null)
                throw new ApplicationException("NHibernate Session Not Open.");
        }
 
        private void CloseTransaction()
        {
            if (Transaction == null) return;
 
            Transaction.Dispose();
            Transaction = null;
        }
 
        #endregion
 
        #region IDisposable Members
 
        public void Dispose()
        {
            CloseTransaction();
            CloseSession();
        }
 
        #endregion
 
    }
}

Note that I am using an embedded resource as my "hibernate.cfg.xml" location. Just change this line to use a file system resource, or whatever you want for your hibernate configuration.

I'm still wanting to re-abstract this into a set of objects that let's me be concerned with transactions and queries at a business level. One step at a time, though. The syntax that I would like to see, at the moment, would be something like this:

public void SomeBusinessValue()
{
    Something something = DoSomething.BusinessRelated();
    SomethingElse somethingElse = SomethingElse();
    Repository.DoTransaction(() =>
    {
        SomeRepository.Save(something);
        SomeOtherRepository.Delete(somethingElse);
    });
}

And if I get really ambitious, I may try to incorporate Castle.Windsor's Automatic Transaction Facility, so that I can have syntax like this:

[Transactional(Transaction.Requires)]
public void SomeBusinessValue()
{
    Something something = DoSomething.BusinessRelated();
    SomethingElse somethingElse = SomethingElse();
 
    SomeRepository.Save(something);
    SomeOtherRepository.Delete(somethingElse);
}

Of course, the more I travel down this path, the more obvious it is how Rhino.Commons' Repository came along. Heh - I'm only about 2 steps away from completely re-doing Ayende's UnitOfWork.

In fact, I may try to re-use NHibernateQueryGenerator and go for this syntax:

[Transactional(Transaction.Requires)]
public void SomeBusinessValue()
{
    Something something = Repository<Something>.Find(Where.SomeProperty = someValue);
 
    Something something = DoSomething.BusinessRelated();
    SomethingElse somethingElse = SomethingElse();
 
    Repository<Something>.Save(something);
    Repository<SomethingElse>.Delete(somethingElse);
}

Wouldn't that be fun... I really do like this syntax. In fact, I spent 9+ months working with it on a project because I love the simplicity of the syntax. In the end, though, I did not understand all of the underlying architecture and abstraction and Ayende set up (he includes the ability to plug in any DAL, including Castle.ActiveRecord, NHibernate, etc) and it caused headaches for me.

...

The major problem I have with this syntax, at the moment, is unit testing the Repository object. I either need to hide these details behind an IWhateverRepository interface (complete with Save, Delete and GetByWhatever methods) like I have been doing, or I I'll need to learn how to unit test NHibernate with in-memory database or something... We'll see where this leads.

(side note: how's that for a "ThoughtStream". )

Monday, March 31, 2008 1:22:29 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Agile | Data Access | NHibernate | Unit Testing | UnitOfWork

 Sunday, March 16, 2008

A coworker and I often have conversations about Unit Testing vs. Test Driven Development. Generally speaking, we agree - there are some semantic or mechanical differences in what we're saying, but nothing major and we usually work that out through the conversations, defining what we are saying. Recently he asked if I ever allow myself to write any code without unit tests, or write code before unit testing it. My initial answer was no, not surprisingly. However, after discussing the question and it's implications further, he brought up a good point and a scenario where I highly encourage writing code without tests:

Prototyping (or Spiking, in Agile terms).

I've posted in the past about how I believe that Prototyping A Process is important in software development, so I won't completely re-hash that. Although, the language that I use to describe prototyping may be evolving, the core concepts and process are still in place (the spiking concept is the same as what I called Prototyping).

Here's what ExtremeProgramming.com has to say about Spiking:

"Create spike solutions to figure out answers to tough technical or design problems. A spike solution is a very simple program to explore potential solutions. Build a system which only addresses the problem under examination and ignore all other concerns. Most spikes are not good enough to keep, so expect to throw it away. The goal is reducing the risk of a technical problem or increase the reliability of a user story's estimate.

 

When a technical difficulty threatens to hold up the system's development put a pair of developers on the problem for a week or two and reduce the potential risk. "

This may seem counter to the creed of writing unit tests first and even counter to the creed of not coding for the future. There is a key element in this description, which I believe is not emphasized nearly enough. The code in your spike IS throw-away code. DO NOT copy and paste even one line of code from the spike into the production code.

"Copy and paste is a design error." - David Parnas

When you understand the process, technology or whatever it is that you are learning, well enough, you must step back from that solution and back into your actual project. Then, you continue the test-first process of Test Driven Development - you write your tests for the area that you are covering and then you write the implementation code using the spike as a read-only reference.

So, yes - there is a time and place for writing code without any unit tests; production code is never that place, though.

Sunday, March 16, 2008 11:17:45 AM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: Agile | Test Driven Development | Unit Testing

 Thursday, March 13, 2008

A lot of people ask these questions when they first start unit testing

  • How many unit tests is too many?
  • Do I need to cover every property, every individual method, ever object, every ???

The goal of unit testing is to provide 100% test coverage. The reality of unit testing is that you want 95% or more, test coverage. There are occasions when unit testing that one last line of code is horrendously repetitious or you miss something or accidentally couple something too tightly. But wait... there's more... and those seem like lousy excuses that lead to allowing bad design in your code.

Ultra-Fine Granularity is Horrible

If you are writing your unit tests after you write your production code, or if you are writing your unit tests first but are simply going through the mechanical process switch and it doesn't really matter if you write your tests first or not, then the answer is horrible. You'll end up unit testing way more than you need to. For example, I wrote a login screen last year. This login screen has three fields and two buttons on it: Username, Password, a drop list of locations assigned to the username, a Login button and a Cancel button. How many unit tests do you think should be written for this? ... I wrote 27 unit tests to cover every possible edge case in the presenter that controlled this view. What a giant horrible mess - changing anything in that login screen was almost as bad as not having it unit tested at all (well ok... nothing is that bad)

I ended up unit testing setting an individual property, and then checking to make sure that property was stored correctly. I unit tested individual method calls with only the username set, or only the password set, or only the location set, or only whatever combination of those set. I unit tested loading the list of locations for the username, and ensuring that the location selected is valid for the user. I unit tested what would happen is an invalid location was selected or a null location was selected... every possible edge case was unit tested and it drove bad design into the application because no one wanted to go through the pain of having to change all of those unit tests at that level of granularity.

Step Up To The API

Just unit testing your code is a great way to ensure that you are writing way more unit tests than you need. Chances are, the code you are writing is not very cohesive and you will end up unit testing the read and write of individual properties rather than just unit testing the business value (process) that actually reads / writes the individual properties. That is to say, your unit tests should be written at one or two steps above ultra-fine granularity. Don't test the individual properties, test that API that you want to call, that has business value.

So, how do you account for 100% code coverage if you are not unit testing the properties and all of the edge cases?

Never write code that you don't need, right now. If you are writing a unit test and the test or the implementation needs a property, then you create that property for that unit test at that time. This does not mean that you write a bunch of get / set property unit tests, just so you can unit test the properties. This means that you specify the business value API in your unit test, and by virtue of having business value, you will likely have various properties associated with the classes in that API. The same is true for edge cases - if the business value of the unit test does not handle the edge cases, then there are no edge cases. Only when you have business value specifying an edge case, do you need to write a unit test for the edge case and possibly modify code to handle the edge case.

Ok, then what happens if your code changes and you don't call that property in the original unit test, anymore?

Never leave dead code in your system. Ever. Period. End of discussion. If you change your unit tests because the design of the object(s) change, and you are no longer using a property - delete the property! If you delete it and you find that you can't compile the code any longer because other parts of the system need that property, then you need to evaluate whether or not that property is really providing value to those other places vs. changing those other places to match the new design.

Test First vs. Test After

A big part of figuring out how many unit tests you need is understanding the functionality of the system. You should be writing a unit test for every functional point of the code, achieving 100% code coverage. The problem with the original question of how many unit tests to write, though, is that there is a hidden assumption in that question:

"I wrote my code, now how many tests do I need, to cover it correctly?"

This question is an underlying problem in Unit Testing and simple Test First development. If you are just unit testing your existing code or only going through the mechanical process switch of writing a unit test first, but not really using the test to drive your design, then you are likely not going to see some of the major benefits of Test Driven DESIGN / Development: not writing code you don't need, and creating the API that you want to call instead of the API coming together haphazardly as a bi-product of writing code first.

When you take the step up to unit testing the API, it becomes more apparent that you really want to specify the API before you write it. If you specify the API before you write it, then you are one step closer to true Test Driven Development. Don't expect the test to design your code for you. Use the test to flesh out your design before you write any code.

Test Driven DESIGN / Development

Would you rather:

Write 50+ lines of code into your model, then write a unit test that shows an ugly API causing you to go back to the code and re-write it in the hopes that it will produce a better API, most likely repeating this process once or twice until you get frustrated with changing your code because it takes so long

or

Write 5 lines of unit test code, specifying the API that you want, realizing that it's not going to work and changing 2 or lines of that test, going through this cycle 5 or 6 times until you have the API that you really do want to call; then implementing the API in the 50+ lines of code and being done with it

I'll take #2. I don't like rewriting large chunks of code. Rewriting 2 or 3 lines of code is easy - I'll do that any minute of any day. Chances are, if you are willing to write the correct number of unit tests by specifying the higher level API in your unit tests, you will gravitate toward designing your API in your unit tests.

TDD Misconception:

TDD is NOT a design tool. It is not "the answer". Is will not design your application for you. It will not solve your problems for you. If you don't know how to design software, then you need to get some training on design patterns, loose coupling through single responsibility and separation of concerns, and various other core foundations of good Object Oriented Development.

In reality, Test Driven Development is just an easier way of saying this:

"Design your API in the context of a unit test, so that you have your API implementation covered by unit tests before you even write the implementation."

Conclusions:

In the end, we can answer the original questions from this post by re-stating Test Driven Development as a software development guideline:

"Design via code, unit testing 100% as you go."

Thursday, March 13, 2008 1:45:25 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Agile | Model-View-Presenter | Test Driven Development | Unit Testing

 Saturday, March 08, 2008

I just can't help myself... I had to flesh out the Account Transfer behavior from my previous post. I was interested in two things:

  1. Adding a second set of Acceptance Criteria for a valid transfer
  2. Implementing the crazy looking "account.Transfer(ammount).To(account)" syntax

Expanded Acceptance Criteria

Existing User Story:

As an account holder,
I want to transfer money between accounts
So that I can avoid overdraft fees

Acceptance Criteria:

  1. Given a transfer between accounts,
    When the requested transfer amount is greater than the originating account's balance
    Then the transfer should fail and the balance of the originating and receiving accounts should not change
  2.  

  3. Given a transfer between accounts,
    When the requested transfer amount is less than the originating account's balance
    Then the transfer is successful, the originating account is debited the transfer amount and the receiving amount is credited the transfer amount

Implementing The Transfer.To Syntax

This was the fun part, really - seeing if I could implement the API that I wanted to see. It turned out to be significantly easier than I had thought it would be.

I started with the Account object, and added the "Transfer" method. I knew that this method needed to return an object so that I could have the "To" method accept an Account object. A few moments of thinking this through and I decided to go with an object called TransferCriteria. This would let me collect all of the information that I need, about the transfer.

public TransferCriteria Transfer(double ammount)
{
    TransferCriteria criteria = new TransferCriteria(this, ammount);
    return criteria;
}

The end-goal of this syntax model is to return an AccountTransfer object, directly. So, the TransferCriteria.To method then creates an AccountTransfer object, using the TransferCriteria.

public AccountTransfer To(Account receivingAccount)
{
    ReceivingAccount = receivingAccount;
    return new AccountTransfer(this);
}


In the end, I have an AccountTransfer object that contains all of the information I need - the originating account, the receiving account, and the transfer amount. With that in place, the rest of the code is simple.

Behavior Specification

AccountTransferSpecifications.cs

using AccountSample.Domain;
using NUnit.Framework;
using SpecUnit;
 
namespace AccountSample.Specifications
{
 
    [TestFixture]
    [Concern("Account Transfers")]
    public class When_The_Requested_Transfer_Amount_Is_Greater_Than_The_Originating_Account_Balance : ContextSpecification
    {
 
        #region Context
 
        private const double originatingAccountBalance = 100;
        private const double receivingAccountBalance = 0;
        private const double requestedTransferAmmount = 125.95;
        private Account originatingAccount;
        private Account receivingAccount;
        private AccountTransfer accountTransfer;
 
        protected override void Context()
        {
            originatingAccount = new Account(originatingAccountBalance);
            receivingAccount = new Account(receivingAccountBalance);
 
            accountTransfer = originatingAccount.Transfer(requestedTransferAmmount).To(receivingAccount);
        }
 
        #endregion
 
        #region Observations
 
        [Test]
        [Observation]
        public void The_Transfer_Should_Fail()
        {
            accountTransfer.Status.ShouldEqual(TransferStatus.Failed);
        }
 
        [Test]
        [Observation]
        public void The_Originating_Account_Balance_Should_Not_Be_Changed()
        {
            originatingAccount.Balance.ShouldEqual(originatingAccountBalance);
        }
 
        [Test]
        [Observation]
        public void The_Receiving_Account_Balance_Should_Not_Be_Changed()
        {
            receivingAccount.Balance.ShouldEqual(receivingAccountBalance);
        }
 
        #endregion
 
    }
 
    [TestFixture]
    [Concern("Account Transfers")]
    public class When_The_Requested_Transfer_Amount_is_Less_Than_The_Originating_Account_Balance: ContextSpecification
    {
 
        #region Context
 
        private const double originatingAccountBalance = 100;
        private const double receivingAccountBalance = 0;
        private const double requestedTransferAmmount = 25;
        private Account originatingAccount;
        private Account receivingAccount;
        private AccountTransfer accountTransfer;
 
        protected override void Context()
        {
            originatingAccount = new Account(originatingAccountBalance);
            receivingAccount = new Account(receivingAccountBalance);
 
            accountTransfer = originatingAccount.Transfer(requestedTransferAmmount).To(receivingAccount);
        }
    
        #endregion
 
        #region Observations
 
        [Test]
        [Observation]
        public void The_Transfer_Is_Successful()
        {
            accountTransfer.Status.ShouldEqual(TransferStatus.Success);
        }
 
        [Test]
        [Observation]
        public void The_Originating_Account_Is_Debited_The_Transfer_Amount()
        {
            const double newBalance = originatingAccountBalance - requestedTransferAmmount;
            originatingAccount.Balance.ShouldEqual(newBalance);
        }
 
        [Test]
        [Observation]
        public void The_Receiving_Account_Is_Credited_The_Transfer_Amount()
        {
            const double newBalance = receivingAccountBalance + requestedTransferAmmount;
            receivingAccount.Balance.ShouldEqual(newBalance);
        }
 
        #endregion
 
    }
 
}

Behavior Implementation

Account.cs

namespace AccountSample.Domain
{
 
    public class Account
    {
 
        #region Properties
 
        public double Balance { get; private set; }
 
        #endregion
 
        #region Constructor
 
        public Account(double currentAccountBalance)
        {
            Balance = currentAccountBalance;
        }
 
        #endregion
 
        #region Methods
 
        public TransferCriteria Transfer(double ammount)
        {
            TransferCriteria criteria = new TransferCriteria(this, ammount);
            return criteria;
        }
 
        public void Debit(double ammount)
        {
            Balance -= ammount;
        }
 
        public void Credit(double ammount)
        {
            Balance += ammount;
        }
 
        #endregion
 
    }
 
}

 

AccountTransfer.cs

namespace AccountSample.Domain
{
 
    public class AccountTransfer
    {
 
        #region Vars
 
        private TransferStatus _status = TransferStatus.None;
 
        #endregion
 
        #region Properties
 
        public TransferStatus Status
        {
            get { return _status; }
            private set { _status = value; }
        }
 
        public double TransferAmmount { get; private set; }
 
        public Account OriginatingAccount { get; private set; }
 
        public Account ReceivingAccount { get; private set; }
 
        #endregion
 
        #region Constructor
 
        public AccountTransfer(TransferCriteria criteria)
        {
            OriginatingAccount = criteria.OriginatingAccount;
            ReceivingAccount = criteria.ReceivingAccount;
            TransferAmmount = criteria.TransferAmount; 
            Execute();
        }
 
        #endregion
 
        #region Methods
 
        private void Execute()
        {
            if (TransferAmmount > OriginatingAccount.Balance)
            {
                Status = TransferStatus.Failed;
            }
            else
            {
                OriginatingAccount.Debit(TransferAmmount);
                ReceivingAccount.Credit(TransferAmmount);
                Status = TransferStatus.Success;
            }
        }
 
        #endregion
 
    }
}

 

TransferCriteria.cs

namespace AccountSample.Domain
{
 
    public class TransferCriteria
    {
 
        #region Properties
 
        public double TransferAmount { get; private set; }
 
        public Account OriginatingAccount { get; private set; }
 
        public Account ReceivingAccount { get; private set; }
 
        #endregion
 
        #region Constructor
 
        public TransferCriteria(Account originatingAccount, double transferAmount)
        {
            OriginatingAccount = originatingAccount;
            TransferAmount = transferAmount;
        }
 
        #endregion
 
        #region Methods
 
        public AccountTransfer To(Account receivingAccount)
        {
            ReceivingAccount = receivingAccount;
            return new AccountTransfer(this);
        }
 
        #endregion
 
    }
}

 

And finally, TransferStatus.cs

namespace AccountSample.Domain
{
 
    public enum TransferStatus
    {
        None = 0,
        Failed = -1,
        Success = 1
    }
 
}

Conclusion

I am madly in love with Behavior Driven Development.

Saturday, March 08, 2008 9:11:27 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Agile | Behavior Driven Development | Unit Testing

In A Previous Post, I talked about how I'm jumping on board the BDD wagon, and I gave an example of a TDD style Unit Test that was close to BDD style, based on how I worded the test. I've decided to test that theory and follow the progression from a standard Unit Test as I was writing them, into a BDD test system such as SpecUnit.NET.

Typical Requirement, Typical Test

Let's look at a very basic requirement, derived and stolen from the presentation done by Scott Bellware at the Agile Austin User Group meeting that I attended last week.

If an account holder has multiple accounts and one is low on funds, allow the account holder to transfer funds between accounts. If the amount to transfer is greater than the amount in the originating account, then the transfer should not be allowed and the balance of both accounts should remain the same. This will let the account holder avoid overdraft fees on the account with insufficient funds.

A basic TDD implementation may look like this:

[TestFixture]
public class AccountTransferTestFixture
{
 
    [Test]
    public void TransferFailsIfRequestedAmmountIsGreaterThanOriginatingAccountsBalance()
    {
        double fromAccountStartingBalance = 100;
        double toAccountStartingBalance = 0;
        double requestedTransferAmmount = 125.95;
 
        Account originatingAccount = new Account(fromAccountStartingBalance);
        Account receivingAccount = new Account(toAccountStartingBalance);
 
        TransferStatus transferStatus = AccountTransfer.Transfer(originatingAccount, receivingAccount, requestedTransferAmmount);
 
        Assert.AreEqual(transferStatus.Failed, transferStatus);
        Assert.AreEqual(fromAccountStartingBalance, originatingAccount.Balance);
        Assert.AreEqual(toAccountStartingBalance, receivingAccount.Balance);
    }
 
}

There is nothing particularly wrong with this unit test. It looks like decent code - appears to be well organized, makes good use of separated objects, and checks to see that everything is as it should be.

Change the Test

Now let's change up the test a bit and move it towards BDD style, the way I have been writing my unit tests recently. The first thing we'll need to do is change the name of the test. Secondly, let's rewrite the object model to be a bit more clear on what's really going on with the transfer.

[TestFixture]
public class AccountTransferTestFixture
{
 
    [Test]
    public void WhenARequestedTransferAmmountIsGreaterThanTheOriginatingAccountBalance_ThenTheTransferShouldFailAndTheAccountBalancesShouldNotBeChanged()
    {
        double originatingAccountBalance = 100;
        double receivingAccountBalance = 0;
        double requestedTransferAmmount = 125.95;
 
        Account originatingAccount = new Account(originatingAccountBalance);
        Account receivingAccount = new Account(receivingAccountBalance);
 
        AccountTransfer accountTransfer = originatingAccount.Transfer(requestedTransferAmmount).To(receivingAccount);
 
        Assert.AreEqual(TransferStatus.Failed, accountTransfer.Status);
        Assert.AreEqual(originatingAccountBalance, originatingAcount.Balance);
        Assert.AreEqual(receivingAccountBalance, receivingAccount.Balance);
    }
 
}

The first thing you'll notice is that the Unit Test's name is significantly closer to the business requirement. This is desired, because it allows a develop and a non-developer to both see what this unit test is really supposed to be doing - how the system should behave when something happens. Secondly, notice the differences in the AccountTransfer object. In the first UnitTest, AccountTransfer was used to attempt the actual transfer and return the status of that transfer. In this test, though, AccountTransfer is an object that is produced by the Account.Transfer method. And lastly, notice the change in APIs to do the actual transfer. Remember that in Test Driven Development, you should be designing the API that you want to call - and then you implement it. I want my API to be very expressive - almost english. This particular change is really a matter of preference, though.

The one thing that has not changed is the list of Asserts. We are still checkign to make sure that the transfer status is "Failed" and that the balance of the originating and receiving accounts is unchanged.

Change the Requirement's Format

Now let's take this example into BDD land.

The first thing we need to do is make sure we have enough information to actually test the behavior of the system. This involves creating a User Story from the requirement that we were given. I won't go into depth on User Stories, here. Just keep the basic format of a User Story in mind, borrowed from Dan North:

As a [role], I want [Feature], so that [benefit]

Let's apply this to the requirement, above:

As an account holder,
I want to transfer money between accounts
So that I can avoid overdraft fees

We can't work on user stores alone, though. The only way a User Story can have any value to a software developer, is when we add Acceptance Criteria to the story. Again, I won't go into detail. Here is the basic format that Acceptance Criteria should follow, borrowed from Dan North, again:

Given [context] [and [some more context], …], When [event], Then [outcome] [and [another outcome], …]

Now let's apply the acceptance criteria to our story

Given a transfer between accounts,
When the requested transfer amount is greater than the originating account's balance
Then the transfer should fail and the balance of the originating and receiving accounts should not change

Notice what we have done with the original requirements, compared to the User Story and Acceptance Criteria. Essentially, we have broken the requirement out into two separate parts that provide more value to the business and to the developer. The User Story is the real business value - what do you want to do, and why. The Acceptance Criteria is where the Developer receives the knowledge of how the system should actually work. Both of these are english statements, though. Nowhere in the Story or Criteria, have we specified any language that deals with a computer, software, or any other technical or implementation detail.

Unit Test the Behavior

With the User Story and Acceptance Criteria separated now, we can write the software and test it. Rather than doing standard Test Driven Development and writing a Unit Test, though; let's focus on Behavior Driven Development and test the behavior of this software using the specified behavior.

This example code is still using NUnit as the test framework, to illustrate that point that you don't need a specific BDD test framework. You can fit BDD style tests into a standard xUnit framework. However, you might feel that it is a little mashed-in and not quite the fit that you want.

namespace Given.A.Transfer.Between.Accounts
{
 
    [TestFixture]
    public class When_The_Requested_Transfer_Amount_is_Greater_Than_The_Originating_Accounts_Balance
    {
 
        double originatingAccountBalance = 100;
        double receivingAccountBalance = 0;
        double requestedTransferAmmount = 125.95;
        private Account originatingAccount;
        private Account receivingAccount;
        private AccountTransfer accountTransfer;
 
        [SetUp]
        public void ContextSpecification()
        {
            originatingAccount = new Account(originatingAccountBalance);
            receivingAccount = new Account(receivingAccountBalance);
 
            accountTransfer = originatingAccount.Transfer(requestedTransferAmmount).To(receivingAccount);
        }
 
        [Test]
        public void The_Transfer_Should_Fail()
        {
            Assert.AreEqual(TransferStatus.Failed, accountTransfer.Status);
        }
 
        [Test]
        public void The_Originating_Account_Balance_Should_Not_Be_Changed()
        {
            Assert.AreEqual(originatingAccountBalance, originatingAccount.Balance);
        }
 
        [Test]
        public void The_Receiving_Account_Balance_Should_Not_Be_Changed()
        {
            Assert.AreEqual(receivingAccountBalance, receivingAccount.Balance);
        }
 
    }
 
}

Notice what we have done with the Acceptance Critiera - we've directly turned it into the tests. We have specified how the system will behave with the various part of the criteria being mapped directly to the various parts of the tests. The [context] has been turned into a namespace; the [event] has been turned into the text fixture's class name; and each of the [outcome] has become a test.

But, why bother splitting all of the parts of the behavior specification out like this? Why not leave it as the unit test was in the previous example? The answer is really the business value of the test and the readability / grok-ability of the tests for developers. I can show anyone on the team - a business analyst, the customer, or a developer - the overview of this specification, and it should be easily understood. A business analyst or customer may not understand the technical details of the Assert statement, or the reason that we have variables declared. However, if they see the collapsed code, it becomes very obvious that the developer has implemented the requested Acceptance Criteria for the user story.

image 

Specify the Behavior

Now that we've seen how to stuff a behavior's specification into an xUnit testing framework, let's look at how to implement it in a testing framework that is designed for BDD: SpecUnit.NET.

namespace AccountTransferSpecifications
{
    
    [Concern("Account Transfers")]
    public class When_The_Requested_Transfer_Amount_is_Greater_Than_The_Originating_Accounts_Balance: ContextSpecification
    {
 
        double originatingAccountBalance = 100;
        double receivingAccountBalance = 0;
        double requestedTransferAmmount = 125.95;
        private Account originatingAccount;
        private Account receivingAccount;
        private AccountTransfer accountTransfer;
 
        protected override void Context()
        {
            originatingAccount = new Account(originatingAccountBalance);
            receivingAccount = new Account(receivingAccountBalance);
 
            accountTransfer = originatingAccount.Transfer(requestedTransferAmmount).To(receivingAccount);
        }
 
        [Observation]
        public void The_Transfer_Should_Fail()
        {
            accountTransfer.Status.ShouldEqual(TransferStatus.Failed);
        }
 
        [Observation]
        public void The_Originating_Account_Balance_Should_Not_Be_Changed()
        {
            originatingAccount.Balance.ShouldEqual(originatingAccountBalance);
        }
 
        [Observation]
        public void The_Receiving_Account_Balance_Should_Not_Be_Changed()
        {
            receivingAccount.Balance.ShouldEqual(receivingAccountBalance);
        }
 
    }
 
}

The major differences between an xUnit framework as a SpecUnit framework, is that the idea of Context is a first class citizen. Aside from that and a few changes to the attribute names used, a SpecUnit test class looks surprisingly similar to the behavior test in NUnit. You'll also notice that we're not using Assert.Equals() anymore. Rather, we're taking advantage of .NET 3.5's Extension Methods and providing a expressive statement. This is somewhat of a syntax preference, though.

We can still compress this code and show it to a business analyst or customer. Even better - SpecUnit.NET comes with a simple report generator that produces an HTML report document based on the specification tests, themselves. The output is essentially a cleaned up version of the collapsed code in an HTML format that anyone can read.

Conclusions: xUnit vs. SpecUnit

The real difference between an xUnit Unit Test and a SpecUnit Specification Test is semantics and a few mechanics. Whether you are using an xUnit framework or a SpecUnit framework, Specification Testing and Behavior Driven Development have a significant benefit to the business when compared to Unit Testing and Test Driven Development alone. As I've said before, this does not mean that TDD is dead or irrelevant. This is only to say that TDD has evolved - it has grown an attachment to Domain Driven Design and Scrum project management, giving it a new home and a new life on it's own. Consider the following:

A Unit Test has the connotation of testing an individual unit of code - a System Under Test as some have called it.

When you pass the value "123" into object XYZ's, ABC method, the result is a change to Foo's Bar property and Widget's Digitize method was called.

Specification Testing, and Behavior Driven Development, on the other hand are all about behavior.

In the context of XYZ, when ABC is done, then the Foo's Bar has been Digitized.

Which would you rather show a business analyst, or the customer? Chances are you could explain the details of the first so that they would understand it... and chances are, that they would understand the second without any need for explanation.

Saturday, March 08, 2008 7:04:02 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Agile | Behavior Driven Development | Unit Testing

(reposting a few items from my old blog to my new one)

...

I hereby declare my love affair with Test Driven Development over, and my new infatuation with Behavior Driven Development beginning. Call me a cool-aid drinker, a bandwagon jumper, or whatever you want... I finally get it...

When I write TDD / Unit Test code like this:

[Test]
public void WhenMagic8BallIsShaken_ThenAnAnswerIsGiven()
{
  //insert code and asserts, here.
}

(and yes, this is an actual example of a unit test I wrote last week, during a TDD training session I was doing for some coworkers), what am I really doing? I'm not just doing TDD, I'm not just Unit Testing... I'm specifying the behavior of the system; I'm specifying the experience of using the magic 8 ball; and really, I'm only about one step away from the mechanics of Behavior Driven Development.

It's an eye-opening realization for me, and gets me all kinds of excited and re-invigorated to learn more.

Now, I'm not going to say that TDD is dead or invalid - it's more like saying I finally see how Domain Driven Design and Test Driven Development are truly married together... and then you change the semantics of the name to fit that marriage.

It's also worth noting that this jump, for me, is purely from the engineering perspective so far. I still have no real experience with a true agile development project / process. Although I'm slowly stepping closer to that - the more I see in the engineering practices, the more I see the need for the project management practices.

... more to come, as I travel down this path.

Saturday, March 08, 2008 3:29:00 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Agile | Behavior Driven Development | Unit Testing

(reposting a few items from my old blog to my new one)

...

Another interesting side effect of my conversations with Scott Bellware, today... I'm not sure if he agrees with these conclusions, but I certainly didn't come to them by my own thoughts alone.

My understanding of the Test Lab or QA department in a software development shop has been based on the idea that the QA team members are not developers - and that they shouldn't be, because a developer will write tests that they know will pass. Well, as it turns out - the reason was correct, but the conclusion was wrong.

In reality, a software development project needs to automate every level of testing - all the way out to the point where the actual customer is sitting down and using the software. This includes: Unit Testing, Integration Testing, and UI Testing. Whether or not you distinguish between these three levels is irrelevant; the testing of the system must be automated as much as possible. This leads us to the next question: What is an automated test? Typically speaking, it's code. Who writes code? Software developers. Do you see where this is heading? maybe?

If software is developed by software developers (duh), why is the software that tests the software not written by software developers?

Lets take this to the agile world of 2 week iterations (or sprints or whatever you want to call them). If the software requirements are being defined every two weeks, then the tests are being defined every two weeks as well. If we are automating the tests during these two week cycles, and the tests are written as code, then why are the software developers not writing the tests? The obvious answer is my reason above - the developer will write the test that they know will pass, because they wrote the code that is being tested. So don't let that happen - don't let the developer who is writing the code, write the integration / UI test code. Then, how do we let a developer write the integration / UI test code? Triples Programming.

The standard XP / Agile practice currently has developers working in pairs - one driving the keyboard / mouse, and one thinking two steps ahead. I say we add a third role and a third person to the mix - one developer to write the integration / UI tests at the same time that the unit tests / production code are being written. What you CANNOT do, though, is include that third role in only two people. The moment you break down to two people, you need to remove the integration / UI test writing or you end up with the original dilemma. You also need to ensure that the developers in the triple, are swapping positions on a regular basis - make sure everyone gets a change to drive the keyboard, think ahead, and code the integration tests.

By programming in triples, you get the advantage of specifying the integration tests as soon as the code is functional. You don't lose motivation to write those test, you don't lose clarity of what the functionality is supposed to be, and you don't have to re-discover the same functionality and clarity at a later time with a new set of minds (the QA team).

So, what happens to the QA team? They are still needed, certainly. But now they can focus on their subject matter expertise - the human interaction of manual and random of software testing by using the actual application. i.e. the parts of testing that can't (or shouldn't) be automated.

...

Ok, ok, ok... if you really want to stick with pair programming you can take this concept and assign 2 teams per story; 1 team to unit test / write production code; and 1 team to integration / UI test.

Saturday, March 08, 2008 3:27:51 PM (Central Standard Time, UTC-06:00)  #    Comments [2]. Trackback 
Tags: Agile | Unit Testing

(reposting a few items from my previous blog to my new one)

...

I follow a lot of Agile Engineering Practices, at this point in my career: Test Driven Development, Domain Driven Design, Single Responsibility Principal, Separation of Concerns, Inversion of Control, Dependency Injection, etc. To get to this point, I've basically taught myself - I read blogs, books, example code, and work my butt off to make sure I know what I'm talking about so that I can stay a few steps ahead of my team(s). In all this effort, learning, failure, success and otherwise, I've learned a few key things about software development as it relates to the Agile world.

  1. Unit Testing is an absolute must, even if you don't do Agile
  2. Unit Testing is not Test Driven Development
  3. Test Driven Development is Agile Engineering, not Agile Process
  4. Agile Engineering alone, does not make Agile software development

1. Unit Testing is an Absolute Must

Whether or not you are trying to do any sort of agile software development, or even test driven development; if you do not unit test your code, you are opening your code up for breaking unexpectedly. In the worst case scenario, you are preventing your code base from being able to change with the needs of the business and causing crippling problems by not keeping your code separated appropriately.

Think about the goals of object oriented development: well encapsulated, highly cohesive and low coupled objects that can easily be re-used. These goals are very high, very lofty and they may be pie-in-the-sky dreams for some developers. So how do you achieve such goals? Single Responsibility Principle, Separation of Concerns, and Inversion of Control. All of these practices are much closer to the implementation level of code - they tell us to keep our code as small as possible; only write the code that needs to be written, in this class. When you see code that does not quite fit into the class you are currently writing, you look for a better place to put that code. This means that you need to split data access out of your business processing, user interface out of your business processing, and often times you will need to split your business process out into multiple classes.

The hard part is, single responsibility, separation of concerns, etc. are not one-time coding practices per class. They are processes that require a continuous series of design, redesign, and refactoring of your code. Don't assume that an object you write, now, will be the same 10 minutes or 10 days from now. If you find yourself in a situation where two objects are very similar, you may have an opportunity to create a better abstraction that can fit both scenarios - whether it becomes a single object, a template pattern, strategy pattern, or other solution.

If you are continuously redesigning your code to fit the business needs, and you are continuously separating your code into more and more classes, creating the high cohesion and loose coupling of true OOD; how do you manage the process and ensure that you are not breaking your application as you go? The answer is simple: Unit Testing. If you are not unit testing your application, then you do not know if the application works until you actually run it and try to use it. If your application is small - one or two classes, one or two screens - this may be reasonable and you may just run the application in it's entirety to see if it works. If your application is medium to large, though - one or two hundred or thousand classes and screens - you will quickly find yourself in a situation where you cannot expect to run the entire application in a reasonable amount of time and you are likely to miss some of the features and functionality if you do try to run it all. The only reasonable way to ensure that your code still works, is to have an automated test suite that can be executed on a regular basis. The easiest way to achieve this, at a very low level, is to do Unit Testing and ensure that your code is 100% covered with the unit tests. By unit testing every line of code in your system, you will have a rapid feedback tool that tells you when you break something. This rapid feedback will allow you to quickly fix anything that is broken, compared to the "run it and see" process.

With all that being said, it's very important to understand ...

2. Unit Testing is not Test Driven Development

Test Driven Development involves Unit Testing. In fact, Test Driven Development doesn't exist without Unit Tests. However, just because you are Unit Testing, that does not mean that you are doing Test Driven Development. When it comes down to it, Unit Testing is all about insurance - make sure your code is covered because change will happen, and change breaks things. Test Driven Development, on the other hand, is all about software design; writing your unit tests first, to drive the design of the software that you are really writing. TDD is not just Unit Testing; TDD is not just Test-First-Development, either. True TDD is the practice of designing the APIs in your code, by writing out the API that you want to see before you try and implement it.

To do any sort of software development, you need to have some basic functional requirements - what is this software going to do, and why? When you start breaking these requirements down into pieces that are small enough to implement, you can begin to see how the software will look - what classes will be there, what processes will run, and how it all fits together.

When you have good requirements it's easy for a developer to see some of the low level code implementation - using whatever design pattern to create these classes, with this code underneath so that this feature can call into them and do something... TDD, though, wants you to step back a few paces. Don't worry about the low level implementation details, yet. Let's focus on how you want to call into the implementation - what is the API that you want to call, in order to do these processes. Rather than looking at a requirement and saying that you don't know what the API will look like because they have not implemented any of the details, TDD forces you to think backwards - you don't know what the implementation is, but here is the API that you want to call.

3. TDD is Agile Engineering Only

There is a huge disconnect from Test Driven Development, to a true Agile software process. Agile Engineering is a great set of practices that every developer should adopt. This includes Test Driven Development, Domain Driven Design, even Pair Programming. However, these engineering practices can and do fit into any software development lifecycle: RUP, Waterfall, iterative waterfall, and everything else you can image, can all have Agile Engineering practices put in place. I would go so far as to say that we shouldn't even call it Agile Engineering - rather, we should just call these good software engineering practices.

To illustrate this - look at the projects that I work on. They are all standard waterfall type projects. We've implemented these engineering practices in every project that I have lead, for the last 2 years, though.

4. Agile Engineering is not Agile Software Development

Real Agile software development is more than just good engineering practices. It encompasses the entire software development lifecycle - from requirements gathering to requirements definition, continuous discussions with the customer to elaborate on those requirements, discussions with the customer to determine what requirements go into what release and iteration, and more discussions with the client to ensure that the software is heading down the path that they actually want. Have you noticed a trend, here? There's a lot of constant, continuous discussion with the customer in real Agile development. This is an absolute must, in Agile work. If you don't stay in regular communications - as in daily, if not more often - then you don't know if the customer is getting what they want.

I've worked on various projects that do some of these - short iterations, continuous integration for unit testing, regular releases to the customer, even pair programming; but I have never worked on a true agile project. It's just not possible to do true agile software development if you don't have complete buy-in and ownership from the entire team - from the customer down to the individual developer. I dream of the day that I'll have a chance to work in an environment like this.

The Future of Agile

Agile engineering, Agile process... how does this all tie together? Where is the knowledge moving and how do we get there? Personally, I'm on board with Behavior Driven Development group. Imagine taking every aspect of Agile, and wrapping it up into one very cohesive set of processes and practices. I get all kinds of excited just thinking about it.

Saturday, March 08, 2008 3:26:08 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Agile | Model-View-Presenter | Unit Testing

Navigation
About Me
View Derick Bailey's profile on LinkedIn

Send mail to the author(s) Contact Me
Archive
<September 2010>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
Derick Bailey
Sign In
Statistics
Total Posts: 115
This Year: 0
This Month: 0
This Week: 0
Comments: 44
Themes
Pick a theme:
All Content © 2010, Derick Bailey
DasBlog theme 'Business' created by Christoph De Baene (delarou)