Saturday, September 25, 2010

Spec Style Unit Tests in C#

Spec style unit tests are unit tests that focus on making the specs clear, and then relating some test code to each part of the spec. The Specs Scala unit test framework is really good at that (e.g. check this earlier post), but I want to be able to do the same in C#.


Lets look at an example: A method for deciding whether a given year is a leap year. The rules for leap years are:


A leap year should
    be any year divisible by 400
    but not other years divisible by 100
    and all other years divisible by 4


In other words the above are the specs for the method. So I would like that to be clear from the unit test. I would also like the unit test to make it clear what test code corresponds to what part of the spec. Therefore I would like the spec to be part of the test, and the test code to be mixed right into that spec text. Something like:


"A leap year" should
{
  "be any year divisible by 400" asIn
{
// test code here
}
  "but not other years divisible by 100" asIn
{
// test code here
}
  "and all other years divisible by 4" asIn
{
// test code here
}
}


such that the spec is clearly visible as the strings, and such that the 'asIn' indicates that the code in the following scope tests the part of the spec right before the 'asIn'. To achieve something close to this I've made three simple extension methods on string: 'should', 'asIn' and 'andIn'. Each one of these extension methods take a delegate as an argument. That makes it possible to write this code:

   16             "A leap year".should(() =>
   17             {
   18                 "be any year divisible by 400".asIn(() =>
   19                 {
   20                     // Test code here
   21 
   22                 })
   23                 .andIn(() =>
   24                 {
   25                     // More test code
   26                 });
   27 
   28                 "but not other years divisible by 100".asIn(() =>
   29                 {
   30                     // Test code here
   31                 });
   32 
   33                 "and all other years divisible by 4".asIn(() =>
   34                 {
   35                     // Test code here
   36                 })
   37 

Because this is C# there I need to the dots and the arrows ( ()=> ) in there, but I still think the spec is pretty clearly visible. The extension methods themselves are very simple: They basically just execute the delegate passed to them, which means that all the test code snippets in the above will be executed. The complete code for the extension methods is:




    1 using System;
    2 
    3 namespace Specs
    4 {
    5     public static class SpecExtensions
    6     {
    7         public static void should(this string unitUnderTest,
    8                                   Action executableSpecification)
    9         {
   10             Console.WriteLine(unitUnderTest + " should");
   11             executableSpecification();
   12         }
   13 
   14         public static string asIn(this string readableSpecification,
   15                                   Action executableSpecification)
   16         {
   17             Console.WriteLine(@"    " + readableSpecification);
   18             return RunExecutableSpecification(
   19                     readableSpecification, executableSpecification);
   20         }
   21 
   22         public static string andIn(
   23             this string readableSpecification,
   24             Action executableSpecification)
   25         {
   26             return RunExecutableSpecification(
   27                     readableSpecification, executableSpecification);
   28         }
   29 
   30         private static string RunExecutableSpecification(
   31             string readableSpecification,
   32             Action executableSpecification)
   33         {
   34             executableSpecification();
   35             return readableSpecification;
   36         }
   37     }
   38 }


Combining that with NUnit, the test for my leap year checker becomes:




    1 using NUnit.Framework;
    2 
    3 namespace Specs.Test
    4 {
    5     [TestFixture]
    6     public class LeapYearTest
    7     {
    8         [Test]
    9         public void LeapYearSpec()
   10         {
   11             "A leap year".should(() =>
   12             {
   13                 "be any year divisible by 400".asIn(() =>
   14                 {
   15                     Assert.That(LeapYearChecker.IsLeapYear(0),
   16                                 Is.True);
   17                     Assert.That(LeapYearChecker.IsLeapYear(400),
   18                                 Is.True);
   19                     Assert.That(LeapYearChecker.IsLeapYear(800),
   20                                 Is.True);
   21                 })
   22                 .andIn(() =>
   23                 {
   24                     Assert.That(LeapYearChecker.IsLeapYear(-400),
   25                                 Is.False);
   26                 });
   27 
   28                 "but not other years divisible by 100".asIn(() =>
   29                 {
   30                     Assert.That(LeapYearChecker.IsLeapYear(100),
   31                                 Is.False);
   32                     Assert.That(LeapYearChecker.IsLeapYear(100),
   33                                 Is.False);
   34                     Assert.That(LeapYearChecker.IsLeapYear(200),
   35                                 Is.False);
   36                     Assert.That(LeapYearChecker.IsLeapYear(1000),
   37                                 Is.False);
   38                 });
   39 
   40                 "and all other years divisible by 4".asIn(() =>
   41                 {
   42                     for (int i = 0; i < 100; i += 4)
   43                     {
   44                         Assert.That(LeapYearChecker.IsLeapYear(i),
   45                                     Is.True);
   46                     }
   47                 })
   48                 .andIn(() =>
   49                 {
   50                     for (int i = 1600; i < 1700; i += 4)
   51                     {
   52                         Assert.That(LeapYearChecker.IsLeapYear(i),
   53                                     Is.True);
   54                     }
   55                 })
   56                 .andIn(() =>
   57                 {
   58                     for (int i = 1601; i < 1700; i += 4)
   59                     {
   60                         Assert.That(LeapYearChecker.IsLeapYear(i),
   61                                     Is.False);
   62                     }
   63                 });
   64             });
   65         }
   66     }
   67 

The specs are not as easily visible once all the code is there, but I still think its easy to find the specs. What do you think? Is there too much clutter of dots and arrows and stuff? Is the calling back and forth between the test and extension methods too strange? I'm on the fence. One part me really, really likes this. One part of me really, really doesn't.
Oh, and for completeness the code under test is:




    1    public static class LeapYearChecker
    2     {
    3         public static bool IsLeapYear(int year)
    4         {
    5             return year >= 0 &&
    6                 (year % 400 == 0 ||
    7                 (year % 4 == 0 && year % 100 != 0));
    8         }
    9     }

Thursday, September 9, 2010

Don't Stay Stuck

If you write code professionally, you will have days where you find yourself utterly stuck on a problem. In fact, some days coding feels like trying to wade through quicksand: The harder you struggle to get out the more stuck you find yourself. Getting into one of those situations where you are stuck and can't find a way out is perfectly normal. And it is perfectly acceptable for a professional programmer as well. Every programmer finds themselves in those situations from time to time. Getting stuck is a natural part of creative work like programming, and as such we must simply accept that we get utterly stuck now and then. The important part is what you do about it. As with quicksand the trick is to relax a bit, sit back, and realize that you need to seek help. Not all programmers realize this, but the best ones do.
When faced with an insurmountable problem some programmers just press on and try to work through it. That usually means they start thrashing; they run around in circles without getting anywhere. While this might keep them warm, and even make them seem really busy and hard working it doesn't help the project. Some programmers sort of lose interest and start surfing the web or drinking inordinate amounts of coffee. That doesn't help the project either. To get out the situation you're stuck in, you probably need help - I know, I always do. So seek help.
Seeking help can mean a number of things depending on the problem you're facing. If the problem is on the code level try asking a teammate to come and pair with you - or if you're already pairing, ask to switch pairing partner - that extra set of eyes usually helps. If the problem is a design issue, again ask a teammate to help you out, but get up from the keyboard and go to the white board. Again the extra set of eyes - or even just the process of explaining the problem - usually helps. If the problem isn't technical but has to do with say access to the right tools, the right level of support from third parties, or unrealistic deadlines, ask your project manager for help. And if he or she is not able or willing to help, don't be afraid to escalate the problem to his or her boss - it's the professional thing to do. As I said: Seeking help can mean a number of different things.
But whatever you do, don't just stay stuck. Do something about it.

Friday, August 20, 2010

Immediately Functional? -Really?

Following up on my last post I want to focus one point in the second decision diagram in that post. The diagram is a rule of thumb for deciding what you want a framework to implement for you, and it looks like this:

I want to focus on the "immediately functional" box. It says that you only want to use features in a framework that work in your context as they are. What does that mean? What if the feature needs to be configured just right to work in your context? Or needs to be extended through some extension point? Or needs to be modified slightly by cracking open the framework code? Or will work in the next release according to the frameworks roadmap? Lets look a these in turn.
Is configuration OK? Yes. Of course it is...But only to a certain point beyond which you drown, then you're usually better off building the whole feature by yourself. And keep in mind that frameworks that dont ask you to do a lot of configuration, while still implementing enough are (or course) preferable. Conventions are good at that.
Is extending through extension points OK? Yes. Of course it is. Iff its done through supported extension points. If you extend through something that isn't meant to be an extension point, you will probably have a hard time maintaining that extension, and would usually be better off building the whole feature specifically for your purpose.
Is tweaking the framework code itself OK? No, and not even if you're in a position to merge your changes back into the framework. Because even if in that case, you're now the maintainer of part of the framework, which is not what you set out to be, when you chose to use a framework. In this case you're better off building your own and maintaining that at your own pace, and according to your own needs.
Is waiting for a feature in the next release OK? It depends...as they say :-). It depends on when you absolutely need the feature, and on when you need to start developing on the feature. In other words it depends on whether you have reached the last responsible moment or not. The last responsible moment is the moment at which you have to make a decision.It not just any moment at which you can make a decision. That's likely too early. It's not simply the last minute, because at that point you dont necessarily have a choice anymore. It's the when you reach the point where you need to start developing the feature but still have time to think your choices through and make a decision. If you dont really need the feature yet, postpone to a later iteration, and decide on whether to use the framework for that feature or not, at that time. Maybe you can postpone long a enough for that new release of the framework to come out. At that point deciding whether to use the implementation in the framework or to build your own is probably easy. If you can't wait that long before starting developing the feature, you might still be able to postpone the framework vs DYI decision: Create a clear interface to what you expect the framework to implement in the next release, and then - when you have to - either use the framework to implement the interface or roll your own implementation. You might even hedge the your bets by defining the interface and simultaneously develop against the interface and rolling your own implementation of the interface. If the framework should be released with a suitable feature while your still working on your own implementation, you have the option to switch without throwing too much away, on the other hand if the framework doesn't release anything suitable you're well underway too.

It's about making the decision at right moment - which is at the last responsible moment because that is when you have the most, and best, information to base the decision on, while still maintaining the freedom to actually decide for yourself.