Oct 13 2011

Things Every Senior .NET Developer Should Know–Introduction

Category: Best Practices | .NETMatt @ 14:27

.NET will officially turn 10 years old in February.  Our platform and our community have matured and grown in that time, and today it is virtually impossible for a developer to truly be an expert in everything .NET-related.  There are, however, several things that I think everyone on the .NET platform, particularly those of us that are arrogant enough to call ourselves “senior” level, should know. 

Part 1 – Object-Oriented Programming

Over the coming weeks (or more likely, months, given how infrequently I manage to blog), I will share with you the things that I assume any senior-level developer in the .NET space is comfortable with.  If you are not familiar with these things, then now is your chance to really step up your game.  Each of these techniques and technologies are things that have aided me greatly in my career, and I think they’ll help you as well. 

I have my short list prepared, but before I dive in (beginning next post), I’d like to hear what others think.  What tools, techniques, technologies, etc. do you assume someone is familiar with when they say they are a “Senior .NET Developer?”

Tags:

Sep 23 2011

What’s in your Definition of Done?

Category: Misc | Best PracticesMatt @ 03:38

Every team, whether you are practicing agile or not, regardless of platform or language, should really have some Definition of Done.  What does it mean for a story/feature/defect/whatever to be “done?”  What things have to happen to achieve “done” status?  Defining these things will help with estimating effort, and it may also help increase the quality of your product.  Here are a few of the things I look for in a Definition of Done.

More...

Tags:

Apr 26 2011

Sync Your Visual Studio Environment Through THE CLOUD

Category: Best PracticesMatt @ 13:51

When you read “THE CLOUD,” I hope the voice in your mind sounded powerful and a bit haughty.  The cloud holds lots of promise (and more than a few perils).  If you find yourself using Visual Studio on multiple machines, you probably spend at least some of your precious time keeping your various development environments in sync, especially if you’ve invested any time in installing useful extensions or customizing Visual Studio to fit your preferences.  Today, I’m going to show you how I have fully synchronized my Visual Studio setup across nearly a half-dozen machines through the magic of THE CLOUD. 

The Challenge

In a typical week, I may find myself using Visual Studio on up to six different machines.  There are certain tools and extensions that I simply cannot live without.  In addition, I like to customize certain Visual Studio settings (I use tabs instead of spaces, for example), and I much prefer the Coding Instinct color scheme over the stock Visual Studio color scheme.  After being inspired by Scott Hansleman’s post on the topic, I’ve even started customizing my Visual Studio toolbars and removing anything I don’t use every day. 

image

That’s a fair amount of customization: extensions, colors, settings, toolbars, windows… I definitely don’t want to keep my various environments in sync by hand.  I’ve tried, and it’s painful.  I inevitably find something that works a little differently on one box from the others, and those inconsistencies annoy me.  What I really want is for Visual Studio to work like Google Chrome, keeping all of my extensions and settings in sync through the magic of THE CLOUD. 

image

Preparing Your Master Environment - Make It So!

With just a little bit of work, I’ve been able to *almost* fully address this challenge.  First, go signup for Dropbox if you don’t have it already, and install it on all your development boxes. 

Next decide which of your development machines will serve as your master environment.  We’ll use this environment as the starting point for syncing through the cloud, but once we’re finished, you’ll be able to make a change in any environment and have it picked up by all your other environments.  We’ll refer to this as your master environment from now on.

Open Visual Studio on your master machine, and enable automatic extension updates.  Go to the Tools menu, then to Options, and find the Extension Manager settings.  Check the “automatically check for updates to installed extensions” setting. 

image

Next, use the Visual Studio Extension Manager to install ExtensionSync

image

ExtensionSync is an add-in that will help you keep most of your Visual Studio extensions synchronized across machines.  It can’t manage extensions that aren’t installed through Visual Studio Extension Manager though, therefore it can’t sync things like Resharper or AnkhSVN

Once you’ve installed ExtensionSync, you need to tell it where to store its data.  Go to the Visual Studio Tools menu, then to Options, then find Extension Sync. 

image

There’s only one option: the directory where you want ExtensionSync to keep your data.  Set this to a new directory that you create within your Dropbox.  Remember that Dropbox automatically synchronizes everything to THE CLOUD.

Now that we have configured ExtensionSync, we need an extension that will help us keep our other settings in sync across our environments.  For this, we’ll use Pepper.  Go back to Visual Studio Extension Manager and install ‘Pepper’. 

image

After installing Pepper, push your settings to THE CLOUD by going to the Visual Studio Tools menu and choosing “Pepper: VS Settings Backup & Sync”.

image

Click the Upload Settings button.  When prompted for a username and password, enter whatever username and password you want to use from now on to keep your settings synchronized.  BE SURE YOU DON’T FORGET YOUR USERNAME AND PASSWORD.  After a few moments, your settings will now be safely stored in THE CLOUD, ready for you to redownload as needed.

Syncing Your Other Environments

The settings for your master environment are now synchronized to the cloud.  We configured ExtensionSync to store its list of extensions via Dropbox, and we stored our remaining settings via Pepper.  All we need to do is install ExtensionSync and Pepper on our other environments, and we’ll be able to keep our extensions and settings synchronized across all the environments. 

Go to the Visual Studio Extension Manager on each of your other development boxes and install ExtensionSync.  Go into the ExtensionSync options (via the Tools –> Options menu) and point it at your shared folder on Dropbox.  ExtensionSync will see that the folder already contains data and will install any missing extensions.  Also be sure that you tell Visual Studio to keep all your extensions up to date automatically (Tools –> Options –> Extension Manager).  Go ahead and restart Visual Studio to complete the setup process.  When you restart, you will find that you now have the “Pepper: VS Settings Backup & Sync” option in your Visual Studio tools menu.  Run this, but this time choose to download your settings. 

image

When prompted, enter your username and password exactly as you entered them when you saved your settings from your master environment.  Pepper will download your settings and apply them.  Repeat this process for any of your other development environments.

Congratulations, your development environments are now synchronized! 

Limitations

While this approach brings much-needed cloud synchronization capabilities to Visual Studio, it isn’t quite perfect.  You still have to manually push/pull settings through Pepper when you make a change.  As long as you aren’t tweaking your settings constantly, this shouldn’t be a problem.  Unfortunately, not all extensions can be synchronized in this manner.  Two of my most heavily-used add-ins, Resharper and AnkhSVN, are not available via the Extension Manager and therefore cannot be kept in sync by ExtensionSync.

Synchronize Even More…

I also happen to be an  avid user of Powershell.  I like my Powershell environment configured a certain way though, and I’ve found more than a small handful of useful functions and scripts over the years.  I’d also like to keep my Powershell environment in sync across my various development environments.  Thanks to the magic of Powershell and Dropbox, this is completely possible!  I’ll be detailing how to set this up in my next post.

Anyway, what are you waiting for?  Go download ExtensionSync and Pepper today and get your settings synchronized through THE CLOUD. 

Tags:

Dec 15 2010

Using An Application Bus To Raise Events

Category: Best Practices | .NETMatt @ 14:38

I’ve been writing recently about the Application Bus pattern and how it’s used in RageFeed.  So far, I’ve shown you how it can be used to send both one-way commands as well as synchronous request-reply commands, enabling you to decouple the pieces of your application.  There’s another type of communication that is even more loosely coupled, and it’s a good fit for scenarios where you want to perform a variety of unrelated actions in response to something occurring in your application.  In this article, I’ll show you how to use the Application Bus to raise and handle events.

The Problem: A Violation Of Principles

Let’s look at a somewhat contrived example.  Suppose in RageFeed, when a new user registers, we need to create the user’s account, send the user a “Welcome” E-mail, send ourselves an E-mail, and send the user a free basket of goodies.  Here’s a possible implementation:

public class CreateUserHandler : IHandle<CreateUserRequest, CreateUserReply>
{
    ...

    public CreateUserReply Handle(CreateUserRequest request)
    {
        var user = new User {Username = request.Username, Email = request.Email};
        user.SetPassword(request.Password);

        _repository.Add(user);

        _dispatcher.SendNewUserActivation(request.Username, request.Email);
        
        _dispatcher.NotifyAdminsOfNewUserRegistration(request.Username);

        _fruitService.SendUserWelcomeBaseket(user);

        return new CreateUserReply {Succeeded = true};
    }
}

Even though we’re using Dependency Injection and leveraging the bus, we’ve still managed to violate several design principles in implementing this requirement. 

Single Responsibility Principle

The Single Responsibility Principle (SRP) states that a class should have exactly one reason to change.   In this case, our command handler actually could change for a lot of reasons.  The class would need to change if we decided to stop sending gift baskets, if we decide we don’t want to be notified when new users join, or if we decide we want to perform additional actions after a user registers.  And that leads us to our next violation…

The Open/Closed Principle

The Open/Closed Principle (OCP) states that classes should be closed for modification, but open for extension.  This means we should be able to add new functionality to an existing class without actually editing the class.  But how can we do that here?? One option would be to make the Handle method virtual, then derive a new class that adds new behavior, but that’s not a clean solution (remember, favor composition over inheritance, meaning look for ways to combine multiple independent classes rather than creating complicated inheritance hierarchies).

So, what can we do?  We need to perform several different actions after a user registers.  We know those actions may change in the future.  What can we do to support our requirements while not violating SRP or OCP?  The answer is simple: events! 

The Solution: Events

Let’s re-examine what our command handler should really be doing.  It should be performing the core “register user” action, and that’s it.  In this case, that means adding the user to the underlying repository.  All the other responsibilities are not part of our core process: the user is still registered even if we don’t perform them.  So,those auxiliary responsibilities are good candidates to refactor.  First, let’s add a new IRaiseEvents interface that our command handler can use to signal interesting events:

public interface IRaiseEvents
{
    void Raise<TEvent>(TEvent @event);
}

Next, let’s utilize this to signal that we’ve added a new user:

public CreateUserReply Handle(CreateUserRequest request)
{
    var user = new User {Username = request.Username, Email = request.Email};
    user.SetPassword(request.Password);

    _repository.Add(user);

    //_events is IRaiseEvents, injected by the IoC container. 
    _events.Raise(new UserRegisteredEvent {User = user});

    return new CreateUserReply {Succeeded = true};
}

Now, let’s add some event handlers to take over the responsibilities that used to live in our command handler:

public class UserActivationEmailSender : IHandle<UserRegisteredEvent>
{
    private readonly IEmailDispatcher _dispatcher;

    public UserActivationEmailSender(IEmailDispatcher dispatcher)
    {
        _dispatcher = dispatcher;
    }

    public void Handle(UserRegisteredEvent message)
    {
        _dispatcher.SendNewUserActivation(message.User.Username, message.User.Email);
    }
}

public class AdminNotifier : IHandle<UserRegisteredEvent>
{
    private readonly IEmailDispatcher _dispatcher;

    public AdminNotifier(IEmailDispatcher dispatcher)
    {
        _dispatcher = dispatcher;
    }

    public void Handle(UserRegisteredEvent message)
    {
        _dispatcher.NotifyAdminsOfNewUserRegistration(message.User.Username);
    }
}

public class WelcomeBaseketSender : IHandle<UserRegisteredEvent>
{
    private ISendFruit _fruitService;

    public WelcomeBaseketSender(ISendFruit fruitService)
    {
        _fruitService = fruitService;
    }

    public void Handle(UserRegisteredEvent message)
    {
        _fruitService.SendUserWelcomeBaseket(message.User);
    }
}

Now we can change what happens when a user registers without having to change our user registration command handler! Another nice benefit is that each action is now a lot easier to test and verify.

Extending the Application Bus With Support For Events

Our IRaiseEvents interface is implemented by the application bus.  We only need to make a few small changes to our existing code.  First, the bus:

public class ApplicationBus : IBus, IRaiseEvents
{
    ...

    public void Raise<TEvent>(TEvent @event)
    {
        var handlers = _registry.GetAllHandlersFor<TEvent>();

        foreach (var handler in handlers)
        {
            try
            {
                handler.Handle(@event);
            }
            catch (Exception ex)
            {
                //TODO: Log this somewhere, but don't rethrow.  The caller doesn't care!
            }
        }
    }
}

Next the registry:

public class MessageHandlerRegistry : IMessageHandlerRegistry
{

    public IEnumerable<IHandle<TMessage>> GetAllHandlersFor<TMessage>()
    {
        try
        {
            return _container.GetAllInstances<IHandle<TMessage>>();
        }
        catch (StructureMapException ex)
        {
            //202 means no suitable type found in the container. 
            if (ex.ErrorCode == 202)
            {
                return new IHandle<TMessage>[0];
            }
            throw;
        }
    }
}

It utilizes the same StructureMap-based conventions for registering event handlers, so we don’t have to make any changes there.  Our event handlers are registered automagically just like our command handlers!

Events or Commands?

Commands and events are handled very similarly with an application bus, so how do you decide if something should be a command or an event?  A command implies that exactly one handler will receive the command and do something with it.  In RageFeed, if you send a command and no one handles it, it’s an error.  Conversely, an event may not be handled at all.  It is handled by zero or more handlers, and the source of the event doesn’t care: it raises the event, then goes on about it’s business.  Events could be implemented asynchronously, even in an application bus, by spawning background threads for each event handler.  If you have event handlers that take a while to execute, this is something you should consider, and it’s an easy change to make should the need arise later.

This is a pretty barebones implementation of events.  If you wanted to go a little further, I’d recommend adding a base marker interface for your event classes to implement as well as your commands (on the grounds of making things explicit).   The error handling is also very primitive.  If an event handler throws an exception, the calling class doesn’t care, but you would definitely want to capture that information somewhere.


I think that covers it for events!  Use them when you want multiple handlers to perform actions that are not related to a core operation.  Like commands, they’re a great tool for creating loosely-coupled, easy-to-maintain code!

Tags:

Dec 5 2010

RageFeed’s Application Bus, and Why I Built My Own

Category: Best PracticesMatt @ 13:32

In my last article, I introduced the Application Bus pattern, a specialization of the  Message Bus pattern.  I’m employing an Application Bus in RageFeed, the hobby social networking application I sometimes work on.  Today, I’ll show you how the bus utilizes StructureMap for locating message end points and for dispatching messages.  I’ll also explain why I chose to build my own bus instead of leveraging an existing one, such as the bus available in MVCContrib

The RageFeed Application Bus

I showed some of the interfaces from the RageFeed bus last time.  It’s pretty barebones, but it supports both one-way and two-way messaging patterns.  In one-way messaging, the sender does not require any sort of response or acknowledgement.  In two-way messaging (also known as request-reply messaging), the sender sends a message, then waits for a response to be sent back by the message’s handler.

image

Classes that want to send messages over the bus simply use the IBus interface, while classes that want to receive messages implement one of the two handler interfaces.   The registry interface is used by the concrete implementation of IBus to locate message handlers. 

IBus is implemented by MessageBus.  It’s a trivial implementation, but it has met every requirement we’ve had so far:

public class MessageBus : IBus
{
    private readonly IMessageHandlerRegistry _registry;

    public MessageBus(IMessageHandlerRegistry registry)
    {
        _registry = registry;
    }

    public void Send<TMessage>(TMessage message)
    {
        var handler = _registry.GetHandlerFor<TMessage>();

        if (handler == null)
        {
            throw new HandlerNotFoundException(typeof (TMessage));
        }

        handler.Handle(message);
    }

    public TReply RequestReply<TRequest, TReply>(TRequest request)
    {
        var handler = _registry.GetHandlerFor<TRequest,TReply>();

        if (handler == null)
        {
            throw new HandlerNotFoundException(typeof (TRequest), typeof (TReply));
        }

        return handler.Handle(request);
    }
}

As you can see, the implementation really is quite simple: it receives a message, asks the registry for a suitable handler, then dispatches it to the handler.  There’s a lot of room for additional features (better error handling, exposing hooks to allow messages to be inspected and/or modified, etc), but we just haven’t had a need for those things yet.

The MessageHandlerRegistry implements (surprise!) IMessageHandlerRegistry, and its job is managing the handlers.  For this, it utilizes StructureMap’s IContainer interface:  

public class MessageHandlerRegistry : IMessageHandlerRegistry
{
    private readonly IContainer _container;

    public MessageHandlerRegistry(IContainer container)
    {
        _container = container;
    }

    public IHandle<TMessage> GetHandlerFor<TMessage>()
    {
        try
        {
        return _container.GetInstance<IHandle<TMessage>>();
        }
        catch (StructureMapException ex)
        {
            //202 means no suitable type found in the container. 
            if (ex.ErrorCode == 202)
            {
                return null;
            }
            throw;
        }
    }

    public IHandle<TRequest, TReply> GetHandlerFor<TRequest, TReply>()
    {
        try
        {
            return _container.GetInstance<IHandle<TRequest, TReply>>();
        }
        catch (StructureMapException ex)
        {
            //202 means no suitable type found in the container. 
            if (ex.ErrorCode == 202)
            {
                return null;
            }
            throw;
        }
    }
}

Again, this class is fairly simple, all the heavy lifting is provided by StructureMap. 

By convention in RageFeed, anything that implements either of the IHandle interfaces is automagically registered; there’s no need to manually register anything.  This convention is accomplished using a StructureMap registry that scans all RageFeed assemblies and wires up message handlers appropriately:

public class MessagingRegistry : Registry
{
    public MessagingRegistry()
    {
        For<IBus>().Use<MessageBus>();
        For<IMessageHandlerRegistry>().Use<MessageHandlerRegistry>();

        Scan(scanner =>
                {
                    scanner.AssembliesFromApplicationBaseDirectory(assembly => assembly.FullName.StartsWith("LazyDeveloperGroup."));
                    scanner.ConnectImplementationsToTypesClosing(typeof (IHandle<,>));
                    scanner.ConnectImplementationsToTypesClosing(typeof (IHandle<>));
                });
    }
}

The “magic,” such as it is, comes from the IAssemblyScanner.ConnectImplementationsToTypesClosing method provided by StrucutreMap.  The method connects all concrete types that implement either handler interface to the closed version of the interface.  It’s essentially doing this, but for every handler type in the entire project:

For<IHandle<LoginRequest,LoginReply>>().Use<LoginHandler>();
For<IHandle<LogoutMessage>>().Use<LogoutHandler>();
//etc...

In the end, the bus enables us to create controllers with actions like this:

public ActionResult Create(CreateForm form)
{
    if (!ModelState.IsValid)
    {
        return View("Index", form);
    }

    var request = new CreateUserRequest {Username = form.Username, Email = form.Email, Password = form.Password};
    var response = _bus.RequestReply<CreateUserRequest, CreateUserReply>(request);

    if (!response.Succeeded)
    {
        return View("Index", form);
    }

    return this.RedirectToAction(c => c.Success());
}

As I said in my previous post, message passing is the loosest form of coupling that can be achieved in software: our controllers are completely decoupled from the core domain logic, which means we can easily reuse our core domain in a Silverlight or desktop version of the app.  We can also distribute the core logic across logical or physical boundaries to increase scalability without having to modify our controllers.

“But Matt, didn’t you just reinvent the wheel?”

There are indeed open-source Application Bus implementations in the wild now, though I only know of one that has attained any sort of widespread use: the MVCContrib bus.  As RageFeed does indeed utilizes MVCContrib, it would have been quite easy to just build on MVCContrib’s bus.  However, I really don’t care for the implementation of the MVCContrib bus.  First, it requires handlers to be manually registered with the bus:

public class ApplicationBus : List<Type>, IApplicationBus
{        
    public new void Add(Type type)
    {
        if (type.GetInterface(typeof(IMessageHandler).Name) == null)
        {
            throw new InvalidOperationException(string.Format("Type {0} must implement the IMessageHandler interface",type.Name));
        }
        base.Add(type);
    }

    ...
}

This is not conducive to the zero-friction development we are attempting to maintain in RageFeed.  We could have built a little bit of infrastructure to automatically register our handlers, but that wouldn’t have addressed my next concern: that the bus must create instances of each handler in order to find a suitable handler for a message.  You can see this behavior here:

public class ApplicationBus : List<Type>, IApplicationBus
{        
    ...
    
    public void Send(IEventMessage eventMessage)
    {
        foreach (var handler in GetHandlersForType(eventMessage.GetType()))
        {
            handler.Handle(eventMessage);
        }
    }
    
    ...

    public IEnumerable<IMessageHandler> GetHandlersForType(Type type)
    {
        foreach (Type handlerType in this)
        {
            var handler = _factory.Create(handlerType);
            if (handler.CanHandle(type))
            {
                yield return handler;
            }
        }            
    }
}

If you have a lot of handlers, this could be expensive, especially if you have handlers that depend on expensive-to-create resources.  Sure, you could rework your handlers to lazily-create such resources, but that’s once again taking us farther away from zero-friction development.  I wanted a bus that just worked without requiring anyone to write code with regard to how the bus functions. 

Note: It’s worth pointing out that MVCContrib’s bus is not trying to be a general-purpose Application Bus.  It exists mainly to support MVCContrib’s Portable Areas feature. 

Bus.Send(new EndOfPostMessage());

Well, that’s it for this week’s month’s quarter’s blog post.  I’ve shown you a very barebones Application Bus implementation utilizing StructureMap.  As RageFeed develops, I expect the capabilities of the bus will grow as we find new ways to utilize it.  I’ll be sure to post more when that happens.  In the meantime, please share your questions and comments below.  Thanks!

Tags:

May 13 2010

Want to be a better developer?

Category: Best Practices | .NETMatt @ 06:44

I've been trying to put together a link list of things that have helped me improve as a developer over the last couple of years.  This is far from complete, but it's a start.  I'm not saying this is an absolute "you have to know these things" list or that it will work for everyone out there, it's just things I've found to be really helpful for me.  As always, your mileage may vary. 

  • SOLID Principles - These principles have helped me a ton.  They aren't rules to be followed blindly, but I've found that understanding the reasoning behind them and trying to strive for code that adheres to them generally makes things easier (and also more fun) in the long run.  Now when I’m faced with a design choice, I usually ask myself which alternative is more SOLID and go with that.  Be sure to check out the SOLID “motivational” posters over at Derick Baily’s blog.
  • Design Patterns – Certain types of problems tend to recur in software development.  For these, we have design patterns.  Getting a handle on design patterns is something that only comes with practice.  You won’t be able to memorize and recognize even the “core” set of patterns immediately, but over time you will likely find yourself recognizing when to apply them more and more often. I strongly recommend Head First Design Patterns (yes, the code samples are in Java, but the patterns themselves are what’s important, and a C# dev should have no problem following along).  It provides a very good introduction to design patterns.
  • Test Driven Development – I think a lot of new developers hear “testing” and immediately glaze over, but I actually enjoy practicing TDD.  It doesn’t just help me test my code, it helps me design my code.  That’s a big advantage that a lot of people overlook.  It also gives me confidence that the class I’m creating does exactly what it is supposed to do, and nothing more.  If you aren’t sure how to do TDD, you can watch one of the various TDD Katas online, such as the String Calculator at Roy Osherove’s site or the Bowling Game at ‘Uncle’ Bob’s site. 
  • Resharper 5 - Resharper is essential for doing C# development in my opinion.  Out of the box, it will suggest lots of little things that can help improve your code.  It helped me learn LINQ by offering to convert ugly for/foreach loops into clean, elegant LINQ expressions, and it finally convinced me that ‘var’ isn’t always evil. 
  • NHibernate and FluentNHibernate - I prefer NHibernate to Castle ActiveRecord these days; the ActiveRecord pattern isn't as flexible or as extensible as an implementation of the repository pattern based on NHibernate, and I’ve run face first into that wall on more than one occasion.  FluentNHibernate makes it a lot easier to get up and running with NHibernate since it hides the XML and provides other nice helpers to get you started.  
  • Lambda expressions - These are essential when working with C# 3.0 or later.  They're a bit hard to grasp at first, but they open up very interesting re-use possibilities, and lots of APIs leverage them heavily. FluentNHibernate uses them to setup mappings, and StructureMap uses them for its embedded Domain-Specific Language (DSL). 
  • Generics - This is an older C# feature, but understanding generics is still just as essential today as ever.  Beyond leveraging the built-in generic classes from the base-class library, learning to wield generics also opens up new avenues for creating clean, extensible, and reusable classes.
  • StructureMap (including its AutoMocking container) - One of the biggest "lightbulb" moments I've had recently was adopting StructureMap and IoC-everywhere.  This totally changed how I code.  Now when I realize a class I'm working on is going to need some other 'service' to fullfill its responsibilities, I simply create a new service interface and add it to my class's constructor.  This makes doing top-down development much easier.  Once I’ve finished the tests and implementation for the class I’m working on, I can turn my attention to creating the class that fullfills the service interface. 
  • LINQ - A lot of people focus on LINQ to SQL, but LINQ is more than that.  LINQ to Objects is incredibly useful. Instead of complicated foreach loops that filter or project objects, I find myself writing short, elegant LINQ queries instead. Be sure you learn about all the various extension methods and keywords, including things like ‘select…into’ and ‘let’. 
  • Moq – Mocking frameworks allow you to configure stubs or fakes that you can substitute for dependencies while testing your classes.  While they can indeed be abused, they are still quite useful.  Moq is my personal favorite for its fluent, lambda-based syntax.  Combine it with the adapter pattern, and you can even use it to fake or stub dependencies on base-class library types.
  • ASP.NET MVC and MVCContrib – If you are going to make an ASP.NET application, do yourself a favor and go the MVC route.  While the drag-and-drop appeal of WebForms can be hard to resist, you will inevitably find yourself fighting its leaky abstractions and lack of flexibility as your application scales.  Out of the box, ASP.NET MVC is still quite bare-bones, and you may find yourself having to focus on issues that are more “plumbing” and less “application”.  Be sure to check MVCContrib before you start reinventing the wheel.  With things like portable areas, fluent control builders, test helpers, and a slew of HtmlHelper extensions, it’s surprisingly easy to build maintainable, testable ASP.NET applications by leveraging MVCContrib and ASP.NET MVC. 

Aside from that, I also follow numerous blogs on development.  If I had to trim Google Reader down to only two dev blogs, they would probably be:

  • Ayende @ Rahien – Creator of more open-source .NET software than probably anyone, Ayende is one of my “code heroes”.  I’ve learned a lot from his blog and by reading the code of his various projects.
  • Los Techies – The number of really smart people blogging here makes it a must-read.  I’ve absorbed a lot of new ideas and information from this place.  

I’m sure I’m overlooking something.  Let me know what you’ve found most helpful in improving your developer chops in the comments.

Tags:

Jan 23 2009

Data Storage: Why is the answer always &quot;relational&quot;?

Category: Best PracticesMatt @ 03:18

I've been thinking a lot about persistence and storage lately, and I think I've finally come to the conclusion that relational databases are almost universally being used incorrectly, and that many times an alternative persistence medium is actually a much better solution.  I think relational databases are good for holding data that needs to be aggregated across (for reporting or other types of heavy analysis), not for things that are inherently object-oriented tasks.  We spend so much time these days trying to work around the object-relational impedance mismatch when we could instead remove the mismatch altogether.

What's happened?  Has my brain been negatively impacted by my return to academia?  Am I missing some magic explanation for why we developers seem to immediately assume that there's going to be a SQL database when we create a new application?  Why aren't we using things like db4Objects and CouchDB instead?  I've used db4Objects and found the performance to be nothing short of spectacular when compared to ORM solutions, and I've heard good things about CouchDB. Are we defaulting to relational databases because that's just "the way things are done"?

I guess maybe it will help if you understand why I'm thinking on persistence.  At my day job, our primary product is basically a combination of data warehouse, search engine, deep-web crawler, and data mining toolset.  The primary underlying storage mechanism is a SQL Server database.  This works pretty well for the reporting types of functions, but not so well for the information retrieval types of functions, such as full-text querying, document viewing, etc; those operations tend to be comparatively slow.  And even the reporting performance is pretty slow because the schema is trying to support our object-oriented view of things instead of the data-oriented view that's really needed for reports.  So, I'm going back to the drawing board and trying to come up with a better persistence strategy.  I'm thinking Lucene for indexing.  I'm thinking db4Objects or something similar for the actual document object storage.  I'm thinking SQL Server for storing only the aggregated information collected by processing the documents, no more of this object-relational mismatch garbage. 

My question is, am I thinking clearly?

Tags:

Jan 7 2009

When good architectures go bad...

Category: Best Practices | What NOT To DoMatt @ 17:44

Today has not been a fun day.  I have spent most of today and a large part of yesterday trying to fix a problem in our system.  The problem seems very simple at first, and indeed we came up with a dozen or so ideas for solutions to the problem.  In the end though, none of the ideas could be implemented given our time constraints.  Why?  How could something that seems so simple be so difficult to fix?  The answer lies in a decision that we made four years ago, a decision that seemed like a great idea at the time: we chose the wrong architecture.

Four years ago, we were designing the "final" version of a massive text and data mining platform after going through three previous major prototype efforts (each consisting of about 4-8 months of development and culminating in a somewhat-working product).  Based on our successes and failures in the previous prototypes, we decided we wanted to try something new.  Instead of writing a bunch of architectural infrastructure, we would jump on the web services band wagon, make everything a service, and stick it all in IIS.  It seemed so simple at the time... we would go with the pipe & filter pattern, using asynchronous web services as the transportation mechanism.  The feeling was that we didn't really need anything overly reliable or performant.  Our system was expected to take weeks to run, processing hundreds of thousands of documents.  We did the math and thought "yeah, this architecture should handle that fine."  Plus, we really thought that using IIS and web services would reduce the amount of architectural and infrastructure plumbing and  management we would have to do.  Everything would be loosely coupled (asynchronous and all), and indeed, it was and is to this very day.  It would be robust in the sense that it could recover from errors, and to a degree, this is true.  If something goes wrong while processing a document, the system will eventually try again.  And since we using IIS as the host, we wouldn't have to write our own hosting services, and again, we sort-of hit the mark.  But there were problems.  Oh man, there are still problems.

Fast forward four years, and I am convinced that our architecture has been more of a hindrance than a help.  Everything is asynchronous and decoupled, but it was a lot of work to get it there.  Did you know you can't send soap messages that are 50 MB long by default (at least you couldn't with .NET 1.1).  We found that out the hard way.  Did you know that the XML serializer, which .NET uses for web services, fails to escape a whole slew of characters?  Again, we found that out the hard way after a lot of painful debugging.   Do you know what happens when you fire a document off to an asynchronous pipeline?  Neither does the process that sent it!  Is it in there?  Did it come out the other side?  Should I resend it?  The only way we could address that was by "guessing" how long it would take the document to make it through, then essentially looking for it on the other end.  Did it come out?  No?  Then resend it! 

And that, my friends, is what I have spent the last two days working on.  Let's think about that strategy for a second.  We send a document to a pipeline, wait for some amount of time, then look to see if it has come out there other end.  If not, surely that means something went wrong, and the document died somewhere in the pipeline in a burst of exceptiony goodness.  Right?  WRONG.  The document may very well still be in there.  Someone may have fed a patent document in to it that contains a massive DNA sequence.  One of the processes in the pipeline may be faithfully chugging away, trying to figure out what the various letters in the sequence mean.  But we don't know that.  All we know is that the document never made it out the other end, so we have to assume the worst and send another copy in.  Great.  Now we have a second thread faithfully chugging away on the same DNA sequence.  Again, we wait, then look to see if it has come out the other end.  No?  Send it again!    We now have three copies of the document eating up three threads on a four core machine.  One more pass like that, and we have effectively clogged the pipeline.  Throw in 8 more copies for good measure, and you can rest assured that the pipeline is now permanently blocked until IIS is reset.  This is the bug I've been trying like crazy to fix for two days: how does our controlling process (which we weren't even supposed to have to create according to our original architectural grand vision) know what's going on?  There's no good answer.  I thought of a few hacks, but most wouldn't work.  The hack I went with was basically to try to detect documents that *might* contain genetic sequences and ignore them.  In a system that will see hundreds of thousands of documents in a week, I'm pretty confident that things will be filtered that shouldn't have been.

Anyway, the moral of this rambling post is simply this: the importance of architecture, especially in an enterprise application, is critical.  You do not want to get this piece wrong, or whoever takes over for you when you finally go insane from all the hacks you've had to implement to work around the danged architecture will pay for it.  Think through everything: how it will work under normal conditions, how it will work under load, how it will work when under attack, how it will respond to every conceivable error, how flexible it needs to be, how difficult it will be to maintain... do not skimp on this step, or you will be sorry. 

Tags:

Dec 16 2008

Unit Testing in .NET Part 3 - Asserting That Your Code Rocks

Category: .NET | Best Practices | TestingMatt @ 07:52

In the previous entries in this series, you've learned about the basics of unit testing, and you've seen how to create a very basic unit test.  In this post, you will learn how to fully use NUnit's Assert class to create a full suite of unit tests.  This post builds off the sample described in the previous post, so be sure to check it out if you want to follow along.

Asserting Equality

In the last post, you saw one example of how to use the Assert.AreEqual method to verify that two objects are equal.  As you will soon see, most methods on the Assert class have a ton of overloads.  You can think of the method as having two levels of overloads: the first for all the various types you could pass in (it has specific overloads for most primitive types as well as more generic versions that work with anything that derives from object), and the second level for controling the message that is shown when the Assert fails.  The type-based overloads are self-explanatory and are handled by the compiler for you automatically, so we'll ignore those and focus on the overloads that look like Assert.AreEqual(expected,actual,message) and Assert.AreEqual(expected,actual,message,params).  Let's incorporate one of these overloads into our unit test from the last post.  Here's the original, unmodified test:

   1: /// <summary>
   2: /// Verifies that the balance increases
   3: /// by the appropriate amount.
   4: /// </summary>
   5: [Test]
   6: public void Deposit_AddsValueToBalance()
   7: {
   8:     Account account = new Account();
   9:     //account.Balance is currently zero.
  10:     account.Deposit(100);
  11:   
  12:     Assert.AreEqual(100, account.Balance);
  13: }

Let's change our assumption about what the Deposit method should be doing.  Let's say that this is an awesome bank that automatically adds a 10% match to anything that you deposit.  We could just change the first parameter to Assert.AreEqual to 110, but what happens if we run that test?  All you will see is the 'expected (110), actual (100)' message.  It doesn't tell you much about why 110 was expected.  That's where the third parameter comes in handy:

   1: /// <summary>
   2: /// Verifies that the balance increases
   3: /// by the appropriate amount.
   4: /// </summary>
   5: [Test]
   6: public void Deposit_AddsValueToBalance()
   7: {
   8:     Account account = new Account();
   9:     //account.Balance is currently zero.
  10:     account.Deposit(100);
  11:  
  12:     Assert.AreEqual(110, account.Balance, "Deposit bonus was not applied!");
  13: }

Now when you run the test, you will see the helpful message that was supplied as the third parameter to AreEqual.  The fourth parameter, a params array of objects, behaves like the String.Format method: the third parameter becomes a format string, and the fourth parameter is the set of values to insert into the format string.  This could be useful for logging additional information about the unit test failure.

For both double and float types, the AreEqual method has an additional set of overloads that look like Assert.AreEqual(expected,actual,tolerance).  The tolerance parameter allows you to tell NUnit how close two floating-point values have to be in order to be considered equal.  Going back to our Deposit_AddsValueToBalance test, what if the bonus wasn't *quite* 10%, but was more like 9.75989%?  Well, we could calculate exactly what the bonus would be and pass that in as the expected value, then apply it, or we could specify a tolerance of 0.01 and leave the expected value as 110, like so:

   1: /// <summary>
   2: /// Verifies that the balance increases
   3: /// by the appropriate amount.
   4: /// </summary>
   5: [Test]
   6: public void Deposit_AddsValueToBalance()
   7: {
   8:     Account account = new Account();
   9:     //account.Balance is currently zero.
  10:     account.Deposit(100);
  11:  
  12:     Assert.AreEqual(110, account.Balance, 0.01, "Deposit bonus was not applied!");
  13: }

In addition to primitive types, NUnit has some "special" support for Arrays and Collections.  Typically in the .NET world, Equality is determined by an object's Equals method. Derived types are responsible for overriding that method if they wish to define equality as anything other than the default behavior inherited from the object class.  NUnit fudges this definition a bit for Collections and Arrays: two collections (or arrays) are considered equal if they have the same number of items and all their corresponding elements are equal. 

There is a corresponding inverse method to AreEqual called (not surprisingly) AreNotEqual.  The obvious difference is that AreNotEqual verifies that two objects are different from one another.  AreNotEqual has the same set of overloads as its complementary method.

Asserting Sameness

Next up is the AreSame method.  You may be wondering "what's the difference between 'same' and 'equal'?".  Objects A and B are equal if A.Equals(B) returns true.  Remember that by default all objects inherit an Equals method from the base object class, and that derived classes can implement custom equality checks as needed, so the exact definition of equal depends on what you are comparing.  'Same' is much simpler: objects  A and B are the same if they point to the exact same object in memory. 

The difference between 'equal' and 'same' may sound a bit confusing if you aren't comfortable with the concept of pointers and object references, so check the documentation here if you are still unclear.

To demonstrate this difference, let's create a new method that looks up account information and verify that repeated calls to the method return the same account information instance.  NOTE: I am intentionally not doing things in a test-driven manner right now.  I don't want to muddy the waters with trying to explain that concept at the same time I'm explaining the asserts.  A proper treatment of test-driven development is coming Real Soon(tm)!

First, let's add some new properties to our Account class along with an overloaded Equals method:

   1: /// <summary>
   2: /// A bank account.
   3: /// </summary>
   4: public class Account
   5: {
   6:     #region Public Properties
   7:  
   8:     /// <summary>
   9:     /// The ID of the account.
  10:     /// </summary>
  11:     public int AccountID { get; private set; }
  12:  
  13:     /// <summary>
  14:     /// The name of the account owner.
  15:     /// </summary>
  16:     public string Owner { get; private set; }
  17:  
  18:     /// <summary>
  19:     /// The current account balance.
  20:     /// </summary>
  21:     public float Balance { get; private set; }
  22:  
  23:     #endregion
  24:  
  25:     #region Public Methods
  26:     
  27: ----Snip----
  28:  
  29:     /// <summary>
  30:     /// Compares the current object to the specified object.
  31:     /// </summary>
  32:     /// <param name="obj"></param>
  33:     /// <returns>True if the accounts have the same AccountID,
  34:     /// false otherwise.</returns>
  35:     public override bool Equals(object obj)
  36:     {
  37:         Account account = obj as Account;
  38:  
  39:         if (account == null)
  40:         {
  41:             return false;
  42:         }
  43:         else
  44:         {
  45:             return AccountID == account.AccountID;
  46:         }
  47:     }
  48:  
  49:     /// <summary>
  50:     /// When you override Equals, you have to override
  51:     /// GetHashCode, too...
  52:     /// </summary>
  53:     /// <returns></returns>
  54:     public override int GetHashCode()
  55:     {
  56:         return AccountID.GetHashCode();
  57:     }
  58:  
  59:     #endregion
  60: }

Next, let's add a method to look up and return a 'dummy' Account object on demand:

   1: /// <summary>
   2: /// Gets the specified account.
   3: /// </summary>
   4: /// <param name="accountID"></param>
   5: /// <returns></returns>
   6: public static Account Lookup(int accountID)
   7: {
   8:     return new Account {AccountID = accountID, Owner = "John Doe"};
   9: }

Finally, let's create our test:

   1: /// <summary>
   2: /// The Lookup should return the exact same instance
   3: /// for all lookups on a specific ID.
   4: /// </summary>
   5: [Test]
   6: public void Lookup_ReturnsSameInstance()
   7: {
   8:     Account account = Account.Lookup(1);
   9:  
  10:     Assert.AreSame(account, Account.Lookup(1));
  11: }

Go ahead and build the project and run the test.  What happened?  The test failed because even though we are returning an identical object for both calls, we aren't actually returning the same object.  Let's correct that by storing some static dummy Account instances; we'll return one of these instead of creating a new instance from now on:

   1: /// <summary>
   2: /// These are our dummy accounts.
   3: /// </summary>
   4: private static Account[] mAccounts = new Account[]
   5: {
   6:     new Account{ AccountID = 1, Owner = "John Doe" },
   7:     new Account{ AccountID = 2, Owner = "Jane Doe" }
   8: };
   9:  
  10: /// <summary>
  11: /// Gets the specified account.
  12: /// </summary>
  13: /// <param name="accountID"></param>
  14: /// <returns></returns>
  15: public static Account Lookup(int accountID)
  16: {
  17:     //Arrays are 0-based, accountIDs are 1-based, so we shift them.
  18:     return mAccounts[accountID - 1];
  19: }

Build and re-run the test, and you should get a success message.

Similar to the AreEqual method, the AreSame method has a logical inverse: the AreNotSame method. 

Asserting Greatness

NUnit includes four methods (with overloads) for asserting various inequalities: Greater, GreaterOrEqual, Less, and LessOrEqual.  The intent of these methods should be obvious, but they differ in one major one from the other assertions we've seen so far.  Recall that the basic versions of both AreEqual and AreSame took an expected argument first and the actual value second.  Applying that same logic, you might expect that expressing the inequality x is greater than y would look like Assert.Greater(y,x), but it's actually the opposite.  I can't tell you how many times I've seen this inconsistency bite developers; it doesn't help that the parameters have less-than-helpful names, like arg1 and arg2.  I don't know why they couldn't have used something more obvious and intuitive, like maybe left and right...

Enough complaining, Let's write some code!  Let's add a new deposit to our account class called RandomDeposit.  This method is very different from our standard Deposit method.  Instead of depositing the specified amount, RandomDeposit will deposit a random amount that is anywhere from 0.5 to 1.5 times the specified amount.  The method looks like so:

   1: /// <summary>
   2: /// Deposits a random amount that is between 0.5 
   3: /// and 1.5 times the specified amount.
   4: /// </summary>
   5: /// <param name="amount"></param>
   6: public void RandomDeposit(float amount)
   7: {
   8:     Random rand = new Random();
   9:     double multiplier = rand.NextDouble();
  10:  
  11:     Balance += (float)(amount*(0.5 + multiplier));
  12: }

Because of the randomness in the method, it's going to be very hard to write a unit test using the Assert.AreEqual method.  Instead, we'll use the GreaterOrEqual method to assert that the deposited amount is at least 0.5 times the amount we deposited.  Here's the unit test:

   1: /// <summary>
   2: /// The method should deposit between 0.5 and 1.5
   3: /// times the specified amount.
   4: /// </summary>
   5: [Test]
   6: public void RandomDeposit_DepositsExpectedAmount()
   7: {
   8:     Account account = new Account();
   9:  
  10:     account.RandomDeposit(100);
  11:     Assert.GreaterOrEqual(account.Balance, 50);
  12:     Assert.LessOrEqual(account.Balance, 150);
  13: }

If you aren't already building and testing by habit, go ahead and build the project and run the new test. 

Asserting Typeiness (If Steven Colbert can do it, so can I!)

The Assert class includes methods for asserting things about the type of an instance.  You can check whether or not an object is of a given type using the IsInstanceOfType method.  The first parameter is the expected type of the object, the second parameter is the actual object.  Let's make our Account class implement the ICloneable interface, then write a test to verify that our clone actually is of type Account:

   1: /// <summary>
   2: /// A bank account.
   3: /// </summary>
   4: public class Account : ICloneable
   5: {
   6: ----SNIP----
   7: /// <summary>
   8: /// Clones the current account.
   9: /// </summary>
  10: /// <returns></returns>
  11: public object Clone()
  12: {
  13:     return new Account {AccountID = AccountID, Balance = Balance, Owner = Owner};
  14: }
  15: ----SNIP----
  16: }

Here's the corresponding test case:

   1: /// <summary>
   2: /// Verifies that a complete clone of the account
   3: /// is returned.
   4: /// </summary>
   5: [Test]
   6: public void Clone_ReturnsAccountClone()
   7: {
   8:     Account account = Account.Lookup(1);
   9:  
  10:     object clone = account.Clone();
  11:  
  12:     Assert.IsInstanceOfType(typeof (Account), clone);
  13: }

The IsInstanceOfType and IsAssignableFrom methods are very similar.  Under the covers, they're just calling the corresponding members of the System.Type class.  Check the documentation on MSDN if you are curious about the subtle differences between the two methods, but for the most part, you can use them interchangeably. 

As with most assert methods, there are various overloads of both IsAssignableFrom and IsInstanceOfType.  Each also has a set of complementary Not methods: IsNotAssignableFrom and IsNotInstanceOfType.

Asserting Nothingness

Sometimes the right result is a null result.  Let's look again at our Account.Lookup method.  Right now, we're not really handling the case of an account ID that doesn't exist.  Let's modify the code so that it returns null when given an invalid account ID:

   1: /// <summary>
   2: /// Gets the specified account.
   3: /// </summary>
   4: /// <param name="accountID"></param>
   5: /// <returns></returns>
   6: public static Account Lookup(int accountID)
   7: {
   8:     if (accountID < 1 || accountID > mAccounts.Length)
   9:     {
  10:         return null;
  11:     }
  12:  
  13:     //Arrays are 0-based, accountIDs are 1-based, so we shift them.
  14:     return mAccounts[accountID - 1];
  15: }

And let's write a new test case to verify this:

   1: /// <summary>
   2: /// The lookup should return null when given an ID
   3: /// that doesn't correspond to an account.
   4: /// </summary>
   5: [Test]
   6: public void Lookup_ReturnsNullForInvalidId()
   7: {
   8:     Assert.IsNull(Account.Lookup(0));
   9:  
  10:     Assert.IsNotNull(Account.Lookup(2));
  11: }

Here we've used the Assert.IsNull method.  This is a very simple assert: it simply checks that the parameter is null.  Like everything else, it has a complementary method that will test that something is not null. 

Asserting Truthiness (or Falsiness)

Everything we've asserted so far could actually be expressed using one of the most basic assertions: IsTrue.  This method asserts that a boolean input is true.  It has a complementary IsFalse method that can be used to assert that an input is false.  These methods can be used to test anything that you can express as a boolean condition.  Let's rewrite our previous Lookup test using only IsTrue instead of IsNull to see this:

   1: /// <summary>
   2: /// The lookup should return null when given an ID
   3: /// that doesn't correspond to an account.
   4: /// </summary>
   5: [Test]
   6: public void Lookup_ReturnsNullForInvalidId()
   7: {
   8:     Assert.IsTrue(Account.Lookup(0) == null);
   9:     //Assert.IsNull(Account.Lookup(0));
  10:  
  11:     Assert.IsTrue(Account.Lookup(2) != null);
  12:     //Assert.IsNotNull(Account.Lookup(2));
  13: }

The test should produce identical output because it is logically equivalent to the original.  You might be tempted to just say "forget about all these other asserts, I'll just use IsTrue for everything!", but that's a terrible idea.  The various other assertions give you a lot more information when something goes wrong than IsTrue will.  For example, if GreaterThan fails, it will tell you the values of both parameters.  If you expressed the test using only IsTrue, you would get a very unhelpful message that says "Expected: True, Actual: False".  Sure, you can probably work backwards, add some logging, etc, to figure out what's going on, but why not use the more powerful GreaterThan method to begin with?

Asserting Failuriness

Sometimes you just want a test to fail. Maybe the test isn't finished, or the test couldn't perform some setup correctly, or maybe you need to test for something that is beyond what the built-in assertion methods can handle.  Assert.Fail to the rescue!  Calling this method will instantly fail a test (assuming you haven't done anything silly like wrapped the call with a try-catch block, which we will look at in a future post). 

Asserting Exceptioniness

We've tested that things work so far, but how do we test that things explode?  Right now, there's nothing in our Deposit method that prevents us from depositing negative amounts.  Let's add some logic to throw an exception:

   1: /// <summary>
   2: /// Deposits the specified amount.
   3: /// </summary>
   4: /// <param name="amount"></param>
   5: public void Deposit(float amount)
   6: {
   7:     if (amount <= 0)
   8:     {
   9:         throw new ArgumentOutOfRangeException("amount", amount, "Must be greater than zero.");
  10:     }
  11:  
  12:     Balance += amount;
  13: }

Error-handling code is good, but it still needs to be tested.  NUnit has the ExpectedException attribute that you can use to verify that an exception is thrown, but I hate this attribute.  What the attribute is really doing is verifying that something somewhere in your test case is throwing an exception, not that the exception is actually coming from where you want it to come from.  Instead, I prefer to go with this model:

   1: /// <summary>
   2: /// The method should throw an ArgumentOutOfRangeException
   3: /// if you pass in a negative value.
   4: /// </summary>
   5: [Test]
   6: public void Deposit_ThrowsExceptionOnNegativeAmount()
   7: {
   8:     Account account = new Account();
   9:  
  10:     try
  11:     {
  12:         account.Deposit(-100);
  13:         //The following line will only be executed if the Deposit method
  14:         //failed to throw an exception.
  15:         Assert.Fail("Expected ArgumentOutOfRangeException was not thrown!");
  16:     }
  17:     catch (ArgumentOutOfRangeException)
  18:     {
  19:         //Ok, this is an expected exception.
  20:     }
  21: }

It requires a bit more code, but this version verifies that the correct type of exception is thrown in exactly the right spot.

Other Ways to Assert RoXXorness

The methods we've looked at so far are just the ones that I have found myself using often over the last several years.  NUnit includes other methods that you can use to assert various things about your objects, including:

  • Assert.Contains - Given an object and a list, this method asserts that the collection contains the specified object.
  • Assert.IsEmpty - Given a collection (or a string), asserts that the object contains no items.
  • Assert.IsNaN - Both double.NaN represent the 'not-a-number' condition (often caused by division by zero).  You can test for this condition using the IsNaN assert.

There is even more...

Recent versions of NUnit have added additional utilities, asserts, etc. to simplify your testing.  You can find out more about them here.  We might look at those in a future post, but I really don't find myself using most of them in my day-to-day testing, and I think most developers can get by just fine without them.

In the next post in this series, we'll look at some more complicated testing scenarios as well as common testing problems and strategies for overcoming them.

Tags:

Dec 10 2008

Unit Testing in .NET Part 2 - Your First Unit Tests

Category: Best Practices | TestingMatt @ 04:36

In the last post, you learned the basics of unit testing in .NET: you should understand the intent behind unit testing, you should have a vague idea of what unit tests should look like, and you should have looked at some of the unit testing API options that are available to you.  For the remainder of this series, I'll be focusing specifically on unit testing with NUnit and TestDriven.NET.  If you have chosen to use a different API or tool, you may need to translate the code samples and steps below to match.  If you don't already have NUnit downloaded and installed, do so now.

Adding NUnit To An Existing Project

For now, we'll assume that we are adding unit tests for a project that has already been created.  We'll deal with test-driven development (not to be confused with the test-running tool by the same name) in a future post.  Our tests will be built around an example taken from the NUnit Quick Start, where we have a simple bank API that includes a single Account class.  Here's the code for the class:

   1: using System;
   2:  
   3: namespace NunitDemo
   4: {
   5:     /// <summary>
   6:     /// A bank account.
   7:     /// </summary>
   8:     public class Account
   9:     {
  10:         /// <summary>
  11:         /// The current account balance.
  12:         /// </summary>
  13:         public float Balance { get; private set; }
  14:  
  15:         /// <summary>
  16:         /// Withdraws the specified amount from the account.
  17:         /// </summary>
  18:         /// <param name="amount"></param>
  19:         public void Withdraw(float amount)
  20:         {
  21:             Balance -= amount;
  22:         }
  23:  
  24:         /// <summary>
  25:         /// Deposits the specified amount.
  26:         /// </summary>
  27:         /// <param name="amount"></param>
  28:         public void Deposit(float amount)
  29:         {
  30:             Balance += amount;
  31:         }
  32:  
  33:         /// <summary>
  34:         /// Transfers money to the specified account.
  35:         /// </summary>
  36:         /// <param name="destination"></param>
  37:         /// <param name="amount"></param>
  38:         public void TransferFunds(Account destination, float amount)
  39:         {
  40:             throw new NotImplementedException();
  41:         }
  42:  
  43:     }
  44: }

Create a new project in Visual Studio named 'NunitDemo', add this class to it, and verify that your project builds correctly.  If all goes well, you are now ready to add NUnit to the project.  Assuming you are using Visual Studio, find the "References" folder under the project in the "Solution Explorer" pane.  Right-click on "References" and choose "Add Reference".  From the .NET tab of the "Add Reference" dialog, choose "nunit.framework", then click "Ok".  This DLL contains the attributes and assertion functionality that you need to create your actual unit tests.  At this point, you should see "nunit.framework" listed under the "References" folder.  If so, you are now ready to begin writing test cases!

Sidetrack - Where Do Unit Tests Go?

Before we actually start writing test cases, let's talk about where we're going to put them.  The conventional approach is to put test cases in a completely separate project from the code being tested.  In our example, if our Account class is in a project named "BankSystem", our unit tests would go in a completely separate project called "BankSystem.Tests".  I have two big problems with this approach.  First, it bloats the size of your Visual Studio solution, which means it will take longer to build the solution, and you have twice the number of overhead files (the project file, the documentation file, all the little temp files and folders that Visual Studio and Resharper create, etc).  Second, what if you need to test a class or method that's marked as internal?  You can't do that if your tests live in a completely separate project.

My recommendation is to put the tests in the same project as the code being tested, but do separate the tests into their own namespaces.  For example, our "Account" class is in the "NunitDemo" namespace, so its tests will go in the "NunitDemo.Tests" namesapce.  The downside to this approach is that your test cases will now be distributed along with your actual API, but there's a very easy solution to this: wrap the tests with preprocessor directives.  Depending on your environment and how you deploy your production assemblies, it may be sufficient to simply test whether the DEBUG symbol is defined.  This symbol is defined by default when you build a project in debug mode in Visual Studio.  If you sometimes deploy debug versions of code, then you may want to define a custom symbol to use instead.  For now, we'll assume that we want our unit tests compiled if the DEBUG symbol is defined. 

Writing Your First NUnit Test

At this point, your project should have a reference to nunit.framework, and you should know where you are going to put the test cases.  Let's go ahead and create a test fixture for the Account class.  Within Visual Studio solution explorer, create a new folder called "Tests".  Folders in Visual Studio are typically used to denote namespaces, so any classes you add to this folder will be created in the "NunitDemo.Tests" namespace by default (you can change the namespace after the fact, but that would be WRONG).  Right-click on the new folder, click "Add", then select "Class".  Name the class "AccountTests".  Visual Studio should create the class and open the .cs file for you.  This is just a standard class right now.  We have to make a few changes in order for it to become a test fixture.

First, let's wrap everything in a '#if DEBUG' directive (see the code below if you aren't sure how to do that).  This insures that our new class will only be compiled if the DEBUG directive is defined.  Next, add a using statement for the NUnit.Framework namespace.  NUnit requires that test fixtures be public classes, so go ahead and add the 'public' keyword to the class definition.  Finally, apply the "TestFixture" attribute to the class.  You now have an empty test fixture like so:

   1: #if DEBUG
   2:  
   3: using System;
   4: using System.Collections.Generic;
   5: using System.Linq;
   6: using System.Text;
   7: using NUnit.Framework;
   8:  
   9: namespace NunitDemo.Tests
  10: {
  11:     /// <summary>
  12:     /// Test fixture for <see cref="Account"/>.
  13:     /// </summary>
  14:     [TestFixture]
  15:     public class AccountTests
  16:     {
  17:     }
  18: }
  19:  
  20: #endif

Let's go ahead and add our first test case.  We're going to create a test to verify that the deposit method correctly adds money to the account balance.  Create a method named "Deposit_AddsValueToBalance".  Yes, typically underscores in method names are BAAAD, but this isn't a normal method, it's a test case.  When a test case fails, you want to know immediately what method failed and what the test was supposed to verify, so you need to use descriptive names.  Using underscores allows you to clearly indicate the name of the method being tested and the behavior being tested.  Anyway, you've created your method, now mark it with the "Test" attribute.  Congratulations, you now have an empty test case!  You could run the test now, and it would pass (because it doesn't do anything), but let's add some meat to it first.

Before we write the logic for the test, let's think about exactly what we want to test: we should be able to call the Deposit method, passing in some value X, and the balance should be incremented by that same value X.  How do we test that?  First, we call the method, passing in some constant value.  Next, we use the Assert class from NUnit to verify that the balance increased by that amount.  There are two ways we could do that in NUnit: we can use the so-called "classic model", or we could use the newer "constraint-based" model.  I'm still on the fence about which one I prefer, but for now, we'll stick with the classic model, which means we're going to use the Assert.AreEqual method to check the value of the Balance property after we have invoked the Deposit method.

That's a long paragraph.  If you're confused, maybe this will help:

   1: /// <summary>
   2: /// Verifies that the balance increases
   3: /// by the appropriate amount.
   4: /// </summary>
   5: [Test]
   6: public void Deposit_AddsValueToBalance()
   7: {
   8:     Account account = new Account();
   9:     //account.Balance is currently zero.
  10:     account.Deposit(100);
  11:  
  12:     Assert.AreEqual(100, account.Balance);
  13: }

And that's our test case.  Simple, isn't it?  We're writing code to test code, utilizing the Assert class to verify that expected things are actually happening.  The Assert.AreEqual call will throw an exception if for some reason the Balance property isn't equal to 100.  Assuming you are using TestDriven.NET, you can run your test by right-clicking on either the name of the test method or the name of the fixture class in the code window, then selecting "Run Tests" from the context menu.  TestDriven.NET will launch in the background, run your tests, then spit out the results in the Output pane within Visual Studio.

EOF

So far, we've tested a single, simple method using a single method from the Assert class.  Unfortunately, testing won't always be this simple and straightforward.  In the next post, we'll begin creating more complex test cases as we try out different Assert methods.  We'll also look at some of the other attributes that NUnit supports and how they can help you create tests more efficiently. 

Tags: