What can TDD do for your SRP?

A while ago I had the opportunity to do an MVC pagination kata, which proved to be a real educational and inspirational experience.

One of the bits I had written was a class that created the pagination part as an html string, Pager.ToString(), using a StringBuilder it went through a chain of condition and added some parts accordingly. for example I created a page number link for certain condition, or added the first, previous, next and last page links. These became methods inside my Pager class, so that my ToString() method won’t get too big. For example:

private void GetPageLink(int page)
 {
 string url = _linkProvider.GetCurrentLinkWithPageQuery(page);
_builder.Append("<a class=\"pageLink\" href=\"" + url + "\" >" + page + "</a>");
}

Now came the unit test trying to see whether the StringBuilder was called for each bit that was supposed to be added to our pager. Then, having my mind set to think Mocking-wise, I told myself if I get an interface to replace all these private “builder” methods, my code would become a lot more testable:

public interface IPagerBuilder
 {
 void AddLinkToLast();
 void AddLinkToNext();
 void SetPageNumberLink(int i);
 void AddLinkToPrev();
 void AddLinkToFirst();
 void SetPageLocationTitle(int pageIndex, int pageCount);
 string Build();
 }

And my tests like so (for example):

[Test]
 public void should_have_next_and_last_links()
 {
 paginatedList.Stub(l => l.IsPageCountLessThanRange).Return(false);
 paginatedList.PageIndex = 2;
 paginatedList.Stub(l => l.IsWithinStartingRange).Return(false);
 paginatedList.Stub(l => l.PageCount).Return(5);

 pager.ToString();

 pagerBuilder.AssertWasCalled(b=>b.AddLinkToNext());
 pagerBuilder.AssertWasCalled(b => b.AddLinkToLast());
 }

But hang on, what’s been happening here was quite simply a separation of concerns, my pager class is now responsible for building my pager according to the conditions:

public override string ToString()
 {
 int halfRange = _paginatedList.Range / 2;

 _pagerBuilder.SetPageLocationTitle(_paginatedList.PageIndex, _paginatedList.PageCount);

 if (_paginatedList.IsPageCountLessThanRange)
 for (int i = 1; i <= _paginatedList.PageCount; i++)
 _pagerBuilder.SetPageNumberLink(i);
 else
 {
 if (_paginatedList.PageIndex > 1)
 {
 _pagerBuilder.AddLinkToFirst();
 _pagerBuilder.AddLinkToPrev();
 }

 if (_paginatedList.IsWithinStartingRange)
 for (int i = 1; i <= _paginatedList.Range; i++)
 _pagerBuilder.SetPageNumberLink(i);
 else if (_paginatedList.IsWithinEndRange)
 {
 int startPage = (_paginatedList.PageCount - _paginatedList.Range) + 1;
 for (int i = startPage; i <= _paginatedList.PageCount; i++)
 _pagerBuilder.SetPageNumberLink(i);
 }
 else
 {
 int startPage = _paginatedList.PageIndex - halfRange;
 for (int i = startPage; i < startPage + _paginatedList.Range; i++)
 _pagerBuilder.SetPageNumberLink(i);
 }

 if (_paginatedList.PageIndex < _paginatedList.PageCount)
 {
 _pagerBuilder.AddLinkToNext();
 _pagerBuilder.AddLinkToLast();
 }
 }

 return _pagerBuilder.Build();
}

And the PagerBuilder class is a simple strategy that adds up html strings to a one big happy html string pager, without having to know a thing about when to add this or that bit, why and in what order. Did anyone say Single Responsibility Principal?

Funny thing is, a week after a colleague of mine came to me with the following question: He had a method in a service class that was validating some input from a view, only he had to use some repositories, and he asked me how could he test it. Needless to say, the answer here was a validator interface…

Advertisements
Explore posts in the same categories: MVC, PPP, TDD

Tags: , , ,

You can comment below, or link to this permanent URL from your own site.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: