XNSIO
  About   Slides   Home  

 
Managed Chaos
Naresh Jain's Random Thoughts on Software Development and Adventure Sports
     
`
 
RSS Feed
Recent Thoughts
Tags
Recent Comments

More Fluent Interfaces in Test

Old Test Code:

1
2
3
4
5
6
[Test]
public void ShouldCheckRecipientOfReceivedHeaderIsIntranetServer()
{
    SetHeaderCollectionCount(2);
    Header header1 = CreateMockHeaderAndSetExpectation("Key");
    Header header2 = CreateMockHeaderAndSetExpectation("Received");
1
2
    collection.Stub(x => x.get_Item(1)).Return(header1);
    collection.Stub(x => x.get_Item(2)).Return(header2);
1
2
    factory.Expect(x => x.CreateReceivedHeader(header2)).Return(receivedHeader);
    receivedHeader.Expect(x=> x.IsIntranetServer()).Return(true);
1
2
3
    processor.Process(collection,factory);
    receivedHeader.VerifyAllExpectations();
}
1
2
3
4
5
6
[Test]
public void ShouldCheckIfRecipientOfReceivedHeaderCanBeTrusted()
{
    SetHeaderCollectionCount(2);
    Header header1 = CreateMockHeaderAndSetExpectation("Key");
    Header header2 = CreateMockHeaderAndSetExpectation("Received");
1
2
3
4
    factory.Expect(x => x.CreateReceivedHeader(header2)).Return(receivedHeader);
    collection.Stub(x => x.get_Item(1)).Return(header1);
    collection.Stub(x => x.get_Item(2)).Return(header2);
    receivedHeader.Stub(x => x.IsIntranetServer()).Return(false);
1
2
    receivedHeader.Expect(x => x.IsTrustedRecipient()).Return(true);
    processor.Process(collection, factory);
1
2
    receivedHeader.VerifyAllExpectations();
}

Can you understand what is happening out here? Well it took me quite some time to understand it all. The first thing that caught my attention was the amount of duplication. All this duplication was getting in the way for me to see what was the real difference between the two tests.

Also I was bothered by the fact that the test contained calls to methods at various different levels of abstraction. I really like creating a veneer of domain specific language (method calls) that the rest of my code interacts with. .i.e. method containing calls to methods which are at similar level of abstraction.

Here is what I came up with to make it easy to communicate the intent. Also I tried to hide all the unnesscary stubbing logic. Not worth it staring in my face.

Refactored Code:

1
2
3
4
5
[Test]
public void RecipientOfReceivedHeaderBelongingToIntranetServerIsIgnored()
{
    AddHeader("MessageId");
    AddHeader("Received").FromIntranetServer();
1
2
    Process();
}
1
2
3
4
5
[Test]
public void TrustedRecipientOfReceivedHeaderIsAccepted()
{
    AddHeader("MessageId");
    AddHeader("Received").FromInternetServer().WhichIsTrusted();
1
2
    Process();
}
1
2
3
4
5
[TearDown]
public void VerifyExceptations()
{
    receivedHeader.VerifyAllExpectations();
}
1
2
3
4
5
private WhenHeadersAreProcessed FromInternetServer()
{
    receivedHeader.Stub(x => x.IsIntranetServer()).Return(false);
    return this;
}
1
2
3
4
5
private WhenHeadersAreProcessed FromIntranetServer()
{
    receivedHeader.Expect(x => x.IsIntranetServer()).Return(true);
    return this;
}
1
2
3
4
private void WhichIsTrusted()
{
    receivedHeader.Expect(x => x.IsTrustedRecipient()).Return(true);
}
1
2
3
4
5
6
private void Process()
{
    SetHeaderCollectionCount(headerCount);
    factory.Expect(x => x.CreateReceivedHeader(null)).IgnoreArguments().Return(receivedHeader);
    processor.Process(collection, factory);
}
1
2
3
4
private void SetHeaderCollectionCount(int count)
{
    collection.Expect(x => x.Count).Return(count);
}
1
2
3
4
5
6
private WhenHeadersAreProcessed AddHeader(string key)
{
    Header header = CreateMockHeaderAndSetExpectation(key);
    collection.Stub(x => x.get_Item(++this.headerCount)).Return(header);
    return this;
}

Also see: Fluent Interfaces improve readability of my Tests


    Licensed under
Creative Commons License