Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Building a WPF Application: Part 2
Table of Contents

So let's get back to this whole building a WPF application thing.

A number of things went down since my last post: I was out sick with a stomach bug for few days, my infant son caught the same bug and subsequently we spent a few days in the hospital (he's fine now, it was nothing serious), and I finally caught up on the AAA syntax in Rhino.Mocks.

Changing My Testing Style

Lots of people have blogged about the AAA syntax here, here, and here (to list a few). I won't go in depth, but briefly the idea is that you arrange your unit test thusly:

  • Arrange: do the minimal setup required to execute the test
  • Act: execute the actual code under test
  • Assert: assert that the code did what you expected

I decided to adopt this style. It seems to yield more readable, more focused, and less brittle tests. I rewrote the test from my last post using AAA.  The original test was this:

[TestFixture]
public class The_presenter_for_the_home_feed : TestFixtureBase
{
    private HomePresenter _presenter;
    private IFeedRepository _feedRepository;

    protected override void given_the_context_of()
    {
        _feedRepository = Mocks.StrictMock<IFeedRepository>();
        _presenter = new HomePresenter(_feedRepository);
    }

    [Test]
    public void can_refresh_the_home_feed()
    {
        using (Record)
        {
            Expect.Call(_feedRepository.FetchHomeFeed())
                .Return(new List<Entry>());
        }

        using (Playback)
        {
            _presenter.RefreshHomeFeed();
        }
    }
}

and I rewrote it as this:

[TestFixture]
public class The_presenter_for_the_home_feed : TestFixtureBase
{
    private HomePresenter _presenter;
    private IFeedRepository _feedRepository;

    protected override void given_the_context_of()
    {
        _feedRepository = MockRepository.GenerateStub<IFeedRepository>();
        _presenter = new HomePresenter(_feedRepository);
    }

    [Test]
    public void can_refresh_the_home_feed_when_credentials_are_available()
    {
        _presenter.RefreshHomeFeed();
        _feedRepository.AssertWasCalled(x => x.FetchHomeFeed());
    }
}

Again, you can gather more details about this approach in one of the links above.

One interesting note though is that AssertWasCalled is an extension method and we're using it to assert the method FetchHomeFeed() was actually called on feedRepository.

(I also think that I should not have used StrickMock in the original test, as that added to fragility of the test.)

I tend to think of my code in terms of sentences and paragraphs, at least when it comes to the use of white space. You'll notice as the tests get a little larger that there will usually be three "paragraphs" in the code: arrange, act, assert.

Focusing on the Story

I said in my last post that the core story for this application is to retrieve the home feed. As such, I'd like to take the shortest path to getting that feature fully functional.  The next few steps are roughly:

  • Write a proxy to wrap the existing FriendFeed api, but just enough to fetch the home feed.
  • Write a repository that will manage the home feed data. Even though this seems superfluous at the moment, it's a seam in the application where I will add future functionality (such as caching, logging, etc.).
  • Provide support for authentication.  The FriendFeed api requires a username and remote key for accessing the home feed.

Very soon, I want to be able to launch the application, click a Refresh button, and see my feed. If I haven't provided credentials, I want the application to prompt me for them.

The Credentials Problem

The parts of the story regarding credentials raise some interesting design questions. Let's consider some of the pieces of the puzzle.

The HomePresenter is going to initiate the act getting the home feed. We've already seen that HomePresenter is going to invoke some implementation of IFeedRepository. The repository will talk to the FriendFeed api through a wrapper (IFriendFeedProxy) . Inside the wrapper class is the official .NET FriendFeed client, and it is the class that is really interested in the credentials. It's what talks to the FriendFeed web service, and that needs to be authenticated with the credentials. So at the bottom of this, somewhere in our code, we'll have this:

FriendFeedClient client = new FriendFeedClient("username", "remoteKey");

classesI'm using the Dependency Inversion Principle (which I'll talk about more later). However a consequence of this is that the constructor for HomePresenter takes an IFeedRepository and an IApplicationController.

In turn, my implementation of IFeedRepository, cleverly named FeedRepository, requires an instance of IFriendProxy in its constructor. My implementation of IFriendProxy wraps the official api. Did you follow all of that?

When I first began working through the design, I thought that I'd have to request the credentials from the user at the presenter level, and then pass them down to the repository, then to the proxy which would in turn set them on the actual client. But I could tell quickly that this smelled bad. The repository doesn't need to be concerned with credentials, and neither the HomePresenter. So far there are really just two classes that need to know about credentials: some sort of UI for getting the credentials from the user (that is a presenter of some sort) and FriendFeedProxy.

Oh and what's this IApplicationController interface all about? Um, I'll come back to that in the next post.

Single Source

Ideally, what I want is a single source for the credentials: a class whose sole responsibility is managing the current set of credentials. This lead me to create an ICredentialsSource interface. In order to flesh out what the interface should look like I began writing tests for how the client proxy would interact with it:

[TestFixture]
public class The_client_for_FriendFeed
{
    private const string _username = "your_username";
    private const string _remotekey = "your_remotekey";
    private ICredentialsSource _credentials;
    private FriendFeedProxy _client;

    [SetUp]
    public void given_the_context_of()
    {
        _credentials = MockRepository.GenerateStub<ICredentialsSource>();
        _client = new FriendFeedProxy(_credentials);
    }

    [Test]
    public void can_get_the_home_feed_when_authenticated()
    {
        _credentials.Stub(x => x.UserName).Return(_username);
        _credentials.Stub(x => x.RemoteKey).Return(_remotekey);
        _credentials.Raise(x => x.CredentialsChanged += null, _credentials, EventArgs.Empty);

        var feed = _client.FetchHomeFeed();

        IList<Entry> entries = feed.ToList();
        Assert.That(entries[0].Id, Is.Not.Null);
        Assert.That(entries[0].Title, Is.Not.Null);
        Assert.That(entries[0].Published, Is.Not.Null);
    }

    [Test]
    [ExpectedException(typeof (WebException))]
    public void cannot_get_the_home_feed_when_not_authenticated()
    {
        var feed = _client.FetchHomeFeed();
    }

    [Test]
    public void updates_credentials_when_the_credentials_source_changes()
    {
        //arrange
        _credentials.Stub(x => x.UserName).Return(_username);
        _credentials.Stub(x => x.RemoteKey).Return(_remotekey);

        //act
        Assert.That(_client.DoesClientHaveCredentials, Is.False);
        _credentials.Raise(x => x.CredentialsChanged += null, _credentials, EventArgs.Empty);

        //assert
        Assert.That(_client.DoesClientHaveCredentials, Is.True);
    }
}

These tests live in my IntegrationTests assembly, separate from my "real" unit test is the Specifications assembly. I consider these tests to be integration tests because they actually interact with the web services. They are not run as often as my Specifications.

I found these tests hard to write, and I would appreciate any feedback on how to improve them.

My point here though is to illustrate how these tests led me to create ICredentialsSource. I know that there will be a little more to it, a method perhaps that will allow me to set the credentials, but we'll get to that when we need it.

Right now, the interface looks like this:

public interface ICredentialsSource
{
    string UserName { get; }
    string RemoteKey { get; }
    event EventHandler CredentialsChanged;
}

I obviously need the username and remote key (and I was tempted to create a class that represented them as a unit.) I also discovered that I wanted the credentials source to raise a change notification event so that the proxy client would be aware when the user changed them.

Some other places in the application will actually set the credentials on this source, perhaps a yet-unwritten presenter whose job will be to request them from the user. This really helps to decouple responsibilities and keep the code clean. For this approach to work however, our application will need a single instance of this class. I'll show how I'll handle that when we cover dependency injection.

Next

I had a lot of interruptions trying to complete this post, and I had to go back reread what I've written so far. In doing so, I realized that I ought to take a step back and explain my overall default architecture that I'm using. That will be the subject of my next post; and I promise to get the actual WPF bits soon!

On to Part 3.


Posted 08-16-2008 9:34 PM by Christopher Bennage

[Advertisement]

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)