Posts in  readability

1.10.2014

C# async/await makes reactive testing expressive!

Isolating asynchronous behavior isn't always possible, especially when it comes to creating integration tests. However, with the new async/await features in c# 5, testing reactive interfaces is a breeze and can be very expressive.

FileSystemWatcher and events

FileSystemWatcher is commonly used to monitor for changes to a directory. It's been around since .Net 1.1. Whenever I work with event based interfaces, I prefer to wrap them with an Observable. Testing this often requires an integration test. Here's some code to convert the FileSystemWatcher.Changed event to an observable:

IObservable<FileSystemEventArgs> Changed = Observable
    .FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(h => Watcher.Changed += h, h => Watcher.Changed -= h)
    .Select(x => x.EventArgs);

I'm using this to create an ObservableFileSystemWatcher adapter. I'll be referring to this in the following tests.

The following code is captured in this gist, look at the revision history to see the changes between each of the following samples.

Designing a test

Historically, testing asynchronous behavior required blocking calls and hackery to capture information for our assertions. Here's how we might be tempted to start testing the observable wrapper:

[Test]
public void WriteToFile_StreamsChanged()
{
    using (var watcher = new ObservableFileSystemWatcher(c => { c.Path = TempPath; }))
    {
        FileSystemEventArgs changed = null;
        watcher.Changed.Subscribe(c =>
        {
            changed = c;
        });
        watcher.Start();

        File.WriteAllText(Path.Combine(TempPath, "Changed.Txt"), "foo");

        Expect(changed.ChangeType, Is.EqualTo(WatcherChangeTypes.Changed));
        Expect(changed.Name, Is.EqualTo("Changed.Txt"));
    }
}

To test the Changed observable, we Subscribe to Changed and then capture the last result into a local changed variable. This way we can run assertions on the changed notification. Next, we Start the watcher, create a new file, and verify we get a notification.

However, when we run this test, it fails. The file notification is asynchronous and thus non-deterministic. We don't know if it will happen before or after our assertions are executed.

Waiting for the result

Historically, we'd have to modify this test to wait for the changed notification. We could use a ManualResetEvent to wait:

[Test]
[Timeout(2000)]
public void WriteToFile_StreamsChanged()
{
    using (var watcher = new ObservableFileSystemWatcher(c => { c.Path = TempPath; }))
    {
        var reset = new ManualResetEvent(false);
        FileSystemEventArgs changed = null;
        watcher.Changed.Subscribe(c =>
        {
            changed = c;
            reset.Set();
        });
        watcher.Start();

        File.WriteAllText(Path.Combine(TempPath, "Changed.Txt"), "foo");

        reset.WaitOne();
        Expect(changed.ChangeType, Is.EqualTo(WatcherChangeTypes.Changed));
        Expect(changed.Name, Is.EqualTo("Changed.Txt"));
    }
}

The reset will block the test at the call to WaitOne just before our assertions. When the changed notification happens, Set will be called in our subscriber and the test will complete. To be safe, the test has also been modified to Timeout after 2 seconds.

Now our test works, but it's not pretty :(

Making it expressive with async/await

Thanks to the new c# 5 async/await language features, we can fix this. Here's the new way we can write this test:

[Test]
[Timeout(2000)]
public async Task WriteToFile_StreamsChanged()
{
    using (var watcher = new ObservableFileSystemWatcher(c => { c.Path = TempPath; }))
    {
        var firstChanged = watcher.Changed.FirstAsync().ToTask();
        watcher.Start();

        File.WriteAllText(Path.Combine(TempPath, "Changed.Txt"), "foo");

        var changed = await firstChanged;
        Expect(changed.ChangeType, Is.EqualTo(WatcherChangeTypes.Changed));
        Expect(changed.Name, Is.EqualTo("Changed.Txt"));
    }
}

Observables are awaitable, which means we can wait (non-blocking) for the next item. In this case, we can use FirstAsync().ToTask() to create a Task, that upon completion, will contain the first result of the observable sequence. This task is named firstChanged above. This task could complete at any time. Of course in this case, nothing will happen until we create the test file. We're free to continue setting up the test as we've already indicated the desire to capture the first result!

Next, we Start the watcher, create the test file and then the magic, we use await to wait for the result of our firstChanged task. Once the task is complete, the changed notification will be captured into our changed variable. I love how readable this is 'changed equals wait for the first changed'! Once the first changed notification arrives, the assertions will run and the test will complete.

Strive for Expressive Tests

The historical strategy works, but the new style is more compact and doesn't require so much brain power to understand. This new style makes this test much easier to write and much easier to maintain. Try this out and see how it improves your own testing, let me know what you come up with!

12.29.2013

Refactoring: Renaming Ambiguous Variables When Reading Code

"How many times a day do you find yourself trying to figure out what variables represent because they are named ambiguously?"

12.12.2012

Consistent Formatting via Automatic Tools

Writing is a means to convey information. Most languages, human or code, have a great deal of expressiveness built in by default. Format is expressive too. When format changes, it draws our mental attention to it, thus we should use it when we want to cause a shift in attention, like when a direct quote is italicized, or when we begin a new thought with a new paragraph. However, if we are reckless with our formatting, we can easily confuse readers. If we take the time to keep a consistent format and only change when we intend to, we are much more likely to convey our message to the reader.

Be consistent

It's impossible for the world, let alone a single person, to agree on a specific format. However, within a context, I think most would at least agree to be consistent. I would actually argue that most of us don't care about the specifics so long as it's easy to be consistent. The context is subjective, some examples might be a single file, a series of blog posts, or a particular project at work. The context is actually part of the specifics, so be consistent with it too!

Automate consistency

Manual enforcement is a disaster waiting to happen and it's a waste of time. There are lots of tools to help detect and many to help automatically fix inconsistencies. Even the most basic word processor can determine if you didn't put in a double space at the start of a sentence, and add it if desired. If paragraphs are indented, this can be automated too.

Computer languages

When starting a project, make sure you have an IDE or a tool to format your code. Here are some things to help evaluate a particular tool:

  • Is it integrated with how you write your code?
  • Can you easily execute (shortcut key) the cleanup on the current file(s) or a text selection?
  • Can you version the configuration of specific rules within a context (line wrapping, spacing, indentation)?
    • This allows others to automatically work in a new context, without needing to know the specifics.
    • WebStorm is a fantastic example of an IDE where these settings can be shared with the team.
    • The specifics of format are an artifact of the project, it evolves over time, so you should version that if you want to understand historical formats.
  • Are all of the languages covered?
    • Often, I see people clean up the primary language (c#) but not html and javascript.

Case Study: Blogging

As I was writing this, I realized how crappy it is to format this blog post. So I moved it to markdown, where I can focus on the content and not the presentation, where there are specific conventions already established to automatically format the content. For now I'm converting that to html to post to my blog, I would like to automate that step and wire it into a github repository so it's easy for me to blog about new things and not worry about the publishing step.

12.11.2012

KISS & AJAX Deletes

I run across this type of code often (ASP.Net MVC)

[HttpPost]
public string Delete(ObjectId id)
{
    var record = _Database.Get<Record>(id);
    if (record == null)
    {
        return "No matching record!";
    }
    _Database.Remove<Record>(id);
    return "Deleted record!";
}

If the user is interested in deleting the record, does it matter if someone else beat them to it?

[HttpPost]
public string Delete(ObjectId id)
{
    _Database.Remove<Record>(id);
    return "Deleted record!";
}

Isn't the HTTP 200 OK status code enough to indicate success, the user or the software knows the context of the request it made:

[HttpPost]
public void Delete(ObjectId id)
{
    _Database.Remove<Record>(id);
}

Simple things to think about when reviewing code for simplicity, one line of code is much easier to maintain than seven.