March 2008

A common unit testing pattern, part 3

And this time I’m going to drift into theory-land for a bit, and I’m not particularly fond of theory-land.  I prefer "getting-stuff-done-land," which is quite often located on another continent.

Conceptually, objects are these things that sit in space and receive and spit out messages.  And if we look at our User class in that way, it kind of makes sense.  We define the behavior of the User object as receiving a message to set its name, and when it does so, it should then emit a message that it should be saved.

And this is a pretty convenient way to think of objects.  It also isn’t modeled well by most object-oriented languages.

C++-derived languages handle relationships of "is-a" and "has-a" types very well.  But, what we really want here is a "talks-to-a" relationship.  There’s no real first-class way to do that.

Also, they handle incoming messages very well, by means of the public interface of an object.  But, outgoing messages are a little tougher.  Sure, you can do all sorts of things with message receivers and emitters, but realistically, people are going to use the built-in constructs of the language.  So, if we want to model objects as message receivers (easy) and emitters (not easy), we should do it in as basic a way as possible.

And now we get back to "getting-stuff-done-land."  Looking at our User class from the past two entries, we can look at the interface we define as the outgoing messages that the object can emit.  Viewed in that way, it makes sense that the object would own that interface - who else would?  And why would an outgoing message from a user know anything about a database?

There’s other ways to model an outgoing message, and they all pretty much boil down to function pointers.

First, you can use virtual protected methods to define messages, and then override them in derived classes to translate them to the incoming messages that are desired by another component/object.  This method has the advantages of looking more traditional, but the disadvantage of not being able to mix-and-match receivers at runtime.

Secondly, you can use events and delegates.  Combined with lambda expressions in C# 3, this can be an effective way to define outgoing messages.  It has the advantage of not requiring additional classes, but the disadvantage is that you have to hook up each event individually.  Also, events can provide multiple dispatch, but that can become wonky if you want to remove individual anonymous delegates, so I’m counting that as a neutral.

Uncategorized

Comments (0)

Permalink

A Common Unit Testing Pattern, Part 2

So, reading the last post, it might seem like I’m advocating a lot of extra work to do anything.  Having each class create its own interfaces for everything probably seems a bit insane.  Wouldn’t it be better to define a single, universal interface for, say, a database?

Short answer:  no.  By doing so, you’ll inevitably end up intermingling aspects of the dependency with your core code.  In the User example in the previous post, even if you abstract the DBConnection to an IDatabase, you still have to deal with the fact that you’re now tied to a database, and have intermingled knowledge of the database layout and SQL variant you’re using into your User class.

The problem is that each class has its “natural” language.  The “natural” language of the User class is “save the user with this id and this name” (and whatever other information is appropriate).  The natural language of the database is “run this sql command.”

Just as it would be inappropriate to put code specific to the User object in the database, it’s also inappropriate to put database specific code in the user.

So, instead, what we can do is create small classes that take the output of one class (the User, in this case), and turn it into the input expected by the other class (the database, file system, etc.).  There’s no real extra code required to do this, as all of the code would have to be written ayway.  By doing this, you remove the knowledge of this glue code out of either of the two classes, and allow it to live in its own classes, possibly even its own assemblies.

There are times, though, that you do want to maintain a common interface between classes.  But only do this if the classes in question naturally end up with the same interface, or it’s a “natural” dependency - if you’re writing something that retrieves data and writes to a disk, then a mocked file system is appropriate.  An FTP client would be a good example of this, as there wouldn’t really be a point to writing an FTP client that saved to a database.

Additionally, if the “glue” classes are more than simple pass-through classes, it may be worthwhile to test them more thoroughly, and so mocking their underlying data store may be appropriate.

Uncategorized

Comments (0)

Permalink

A common unit testing pattern

There’s two things you frequently hear when talking to developers about TDD.  It’s either "our code is too complicated, you can’t separate it" or "how can you test a database" (or graphics system, or insert other complicated system).

Here’s an example of code that someone might have in mind.

public class User
{
    private DBConnection connection;
    public string Name
    {
        set { SetName(value); }
    }

    private void SetName(string name)
    {
        this.name = name;
        // other stuff…

        connection.ExecuteSQL("update users set name = ‘" + name + "’ where id = " + id);
    }
}

So, usually someone will want to create a mock object for the database for testing purposes.  That’s one way to do it.  But, I’m not sure it’s the best way.  After all, you want to test your class, not your understanding of the database!

There’s another issue here.  The User class knows waaaaay too much about the database for its own good.  I mean, what if we wanted to save to a file system?  We can’t, at least without serious rework.  While we could replace the database connection with a different type, we’re still tightly coupling to the idea of a database.

What we really want to do is save the user info.  So let’s just make a method that does that.

private void SetName(string name)
{
    this.name = name;
    // other stuff…
    SaveUser();
}

private void SaveUser()
{
    connection.ExecuteSQL("update users set name = ‘" + name + "’ where id = " + id);
}

Okay, that’s a little better.  Now we’ve removed the implementation details of saving the user from the SetName method.  It now pretty much says what, conceptually, we want to do.  All the database stuff is in its own method.

But, being in its own method doesn’t really allow us to change anything.  So, let’s extract an interface.

public interface IUserPersistence
{
    void SaveUser(int id, string name);
}

IUserPersistence persistence;

private void SetName(string name)
{
    this.name = name;
    // other stuff…
    persistence.SaveUser(id, name);
}

And now, our user class doesn’t even have to know about a database at all, or maintain a reference to its connection.  Instead of giving it a DBConnection, we just give it a IUserPersistence object.  We can then test away to our heart’s content, throw whatever exceptions we want, without having to worry about trying to mock anything as heavyweight as a whole database.  We also remove all database specific code from our user class, allowing it to be reused elsewhere.

It’s also conceptually cleaner - the user class now only has to know about the idea of saving itself, not the specific details.

The drawback of this is that it does potentially pollute the API space a bit.  One way to get around this is to set the instance of the interface to protected, and not expose them on the default object.  Then, you can write a test object which inherits from the normal class which exposes a setter.

So, the answer to "how do I mock a database" is simple - you don’t.

Uncategorized

Comments (0)

Permalink

Little Games

Recently, I’ve been finding myself spending way too much time thinking about tools for game development, and not doing enough game development.  So, after I get through the current crunch state I’m in, I think I’m going to set a goal for myself to write a game in a week, no matter how small in scope.

When you have no timeframes and no set deliverables, it’s easy to get lost in theory-land, or what-is-the-best-way-to-do-this-land, or this-tool-isn’t-quite-perfect-land, or any number of other traps.  A hard deadline of a week seems like a great way to force myself past those.

The rules will be simple.  I will set a start date.  Seven days from then, I am done.  Anything not completed, is not completed.

The basic plan I have is to have a minimal basic idea of gameplay, and incrementally develop it primarily using TDD.  I am going to focus on a minimal, complete game before I focus on adding a ton of features.  The hope is that by doing so, I’ll have a game that’s ready to “ship” early on, and additional features will just be that.

I’m allowing myself the time before I start to investigate tools and think of gameplay ideas.  I will not be using the time before the “official” start to write code/do spikes/etc.

I’m looking forward to this.  It’s a chance to look at several of my development theories, and see how they pan out.

OTOH, I don’t think I’ll repeat it indefinitely.  There’s stuff I want to do that’s definitely not possible within a week.

Game development

Comments (0)

Permalink