Saturday, March 27, 2010

According to the unit test purists, your code should never take a dependency on the System.IO namespace directly. In this way you can stub out the entire file system in your unit tests. Yes, I see the point, and I even agree, but unfortunatly I haven´t actually followed through and done this in my own code. Pure laziness.

But now I´m working on a new feature in DataWings (no details yet, I´m planning a "Steve Jobs presents the iPad"-like big splash at some time in the future) where one of the main features has to do with manipulating stuff in the file system. So, DataWings now includes a very small assembly called DataWings.IO which at the moment contains just one single static class wrapping the functionality in the System.IO namespace. The entire class definition is listed at the bottom of this post.

I´m going 100% YAGNI here, and currently only the methods of the System.IO that my exiting new feature needs have been exposed. These are:

File.Exists()

File.ReadAllText()

File.Delete()

File.WriteAllText()

File.ReadAllLines()

Path.Combine()

Directory.GetDirectories()

Directory.GetCurrentDirectory()

An interesting note: I´ve implemented everything as extension methods so that you can say things like: string contents = @"c:\myfile.txt".GetAllContents() . I know that some of you cool cats frown at the notion of extensions methods, but I generally think it´s a thing of grace and beauty. Probably my Smalltalk background showing through.

Another interesting thing: I´ve employed the power of Func<> and Action<> in the code, and IMHO the result is extremly pleasing to the eye: very clean, very easy to understand, very easy to stub the behavior in tests.

So, as mentioned, the whole point is to make the code testable, and here´s a sample of the kinds of tests you can write if your file system accessing code uses the DataWings.IO functionality instead of System.IO directly.

Imagine that I've written a class MyCustomBehavior with a method DoSomeStuff(), and an expected side-effect of this method is that a file with known name and known contents is written to the file system. This code takes a dependency on DataWings.IO and not on System.IO. We want to write a test that checks whether this file actually is written. Here's a unit test that tests this:

[Test]

publicvoid DoSomeStuff_FileAndContentsWrittenAsExpected()

{

// Set up

string expectedContents = "Expected contents.";

string expectedFilename = @"c:\contents.txt";

string writtenContents = null;

string writtenFilename = null;

IoExtensions.FunctionGetCurrentDirectory = () => @"c:\";

IoExtensions.ActionWriteAllText = (path, contents) =>

{

writtenFilename = path;

writtenContents = contents;

};

// Test

MyCustomBehavior.DoSomeStuff();

// Assert

Assert.AreEqual(expectedFilename, writtenFilename);

Assert.AreEqual(expectedContents, writtenContents);

}

And here’s the source:

using System;using System.IO;

namespace DataWings.IO{/// <summary>/// Static class that wraps the functionalty that is found the the System.IO/// namespace, primarily the static classes File, Directory and Path. All/// operations against the file system are handled by action/function invocations,/// and it is possible to set own actions and functions replacing the default/// ones, giving you the ability to stub out the file system./// </summary>publicstaticclass IoExtensions {#region Declarations and Static constructor

Monday, March 8, 2010

SQL Server has the practical concept of identity – you specify a column in your table as being the identity column, and this column automatically gets populated with unique values. This mechanism is most commonly used for the primary key column in the table.

When you use such identity columns you are not allowed to provide a value yourself (at least not by default). This has been a major problem when using the DataBoy functionality in everybody’s favorite tool for data driven DataWings: oftentimes you need to set up known data consisting of several rows in different tables where the data is connected by primary key/foreign key associations. This simply hasn’t been supported in DataWings

Until now, that is: enter DataWings v 1.1. This version contains a few bug fixes, but apart from this version 1.1 introduces return value functionality. This is functionality for getting data back from the database as you insert it, and using this data in subsequent inserts or updates.

This new functionality hinges on the two new commands ReturnValue and BindColumn. I think that a couple of examples should make it clear what this is about. In these samples we assume the existence of two tables: Person with primary key column IdPerson and Address with foreign key column also named IdPerson which refers to the primary key of Person.

So, how to insert a person row and an address row connected to person row. Like this:

The ForImmediateUser() and ToLast() methods are useful for quick usage where the associated columns are inserted directly after one another. The functionality also has the ability of naming return values for more complex usage scenarios:

About Me

Ståle has over 15 years of experience as a programmer/architect, helping to build "enterprise sized" solutions for customers. He works for Computas AS, based just outside of Oslo, Norway.
In a previous life he enjoyed expressing himself with Lisp, but now he mainly concentrates on .NET with some forays into the beautiful world of Smalltalk.