In previous Zero-Friction TDD posts, I've discussed naming SUT and Direct Output variables, as well as the importance of explicitly describing the relationship between input and expected results.

Everything you can do to help the Test Reader understand what's going on increases the quality of the test. Having a naming convention for expectations help in that regard, and it also helps coming up with variable names, thus saving yourself a bit of mental context switching.

My naming convention is to always prefix my expectation variables with the term expected.

[TestMethod]
public void DoStuffWillReturnMessage()
{
    // Fixture setup
    string expectedResult = "ploeh";
    MyClass sut = new MyClass();
    // Exercise system
    string result = sut.DoStuff(expectedResult);
    // Verify outcome
    Assert.AreEqual<string>(expectedResult, result,
        "DoStuff");
    // Teardown
}

In a test like this, the relationship between the input and output is straightforward, but in other cases it may be more complicated. Since tests should explicitly state the relationship between input and output, it may sometimes be necessary to reproduce parts of the SUT's behavior in the test to specify this association.

Do I really recommend duplicating the SUT's code in the test? Isn't this a violation of the DRY principle? And do I really think that embedding complex code in a test is a good idea?

No, no, and no.

What I really mean is best illustrated with an example. Imagine that you want to write an extension method that converts a string to PascalCase. There are several different rules that must be applied to such an algorithm, such as

  • Convert the first letter in a word to upper case
  • Convert the remaining letters in the word to lower case
  • Remove white space

The real algorithm would need to split the string into words along white space boundaries, then loop through this list and perform the conversion for each word, and finally concatenate all the words. However, I don't think you should reproduce this algorithm in any single test.

What you can do instead is to split this behavior into several tests that each test a small part of this specification, carefully avoiding any control flow language features (such as if, switch, for, etc.).

One such test might look like this:

[TestMethod]
public void ToPascalCaseWillConvertFirstLetterToUpper()
{
    // Fixture setup
    string anonymousText = "pLOeh";
    string expectedLetter =
        anonymousText.First().ToString().ToUpper();
    // Exercise system
    string result =
        anonymousText.ToPascalCase();
    // Verify outcome
    Assert.AreEqual<string>(expectedLetter,
        result.First().ToString(), "ToPascalCase");
    // Teardown
}

While the complete implementation of ToPascalCase is more complex, I've extracted a tiny bit of the specification and simulated just that for the special case where there's only one word. Granted, there's a lot of method calls, but I expect that these have already been thoroughly tested, so I use them with confidence. The cyclomatic complexity of the test is minimal.

As an aside, note that I'm using LINQ queries to get the first letter of the string, instead of Substring(0, 1), since I find that the LINQ methods much better communicate intent.

I use a similar naming convention for unexpected values, imaginatively prefixing my variables with the term unexpected.

[TestMethod]
public void CreateThingWillCreateThingWithCorrectGuid()
{
    // Fixture setup
    Guid unexpectedId = Guid.Empty;
    MyClass sut = new MyClass();
    // Exercise system
    Thing result = sut.CreateThing();
    // Verify outcome
    Assert.AreNotEqual<Guid>(unexpectedId, result.Id,
        "CreateThing");
    // Teardown
}

Having a naming convention for expected values not only increases your productivity when writing tests, but also increases test maintainability.


Comments

Hi,

I've read this post a while back, and it was a really helpful way for me to see you suggestion how to still use the "explicit relationship" between input, and output, but preventing yourself from reproducing the implementation by breaking the various parts of the algorithm apart.
I've used that already in plenty of situations, where I would have written a single unit test which was testing multiple scenario's, which could be split up in various isolated unit tests.
However, the other day, I needed to write a view model property that combines 2 properties of that view model in a particular format (see below for the code). I also tried to use this approach, but I couldn't find a way to do that. How would you break that apart in different unit tests?
public string NameAndType { get { return string.Format("{0} [{1}]", Name, ContracteeType); } }
2015-02-03 15:33 UTC

Like this?

[Theory]
[InlineData("Foo""Bar""Foo [Bar]")]
[InlineData("Baz""Qux""Baz [Qux]")]
public void NameAndTypeReturnsCorrectResult(
    string name,
    string contracteeType,
    string expected)
{
    var sut = new MyClass(name, contracteeType);
    var actual = sut.NameAndType;
    Assert.Equal(expected, actual);
}

I'm not sure I understand the question...

2015-02-03 17:03 UTC


Wish to comment?

You can add a comment to this post by sending me a pull request. Alternatively, you can discuss this post on Twitter or somewhere else with a permalink. Ping me with the link, and I may respond.

Published

Wednesday, 11 March 2009 19:54:38 UTC

Tags



"Our team wholeheartedly endorses Mark. His expert service provides tremendous value."
Hire me!
Published: Wednesday, 11 March 2009 19:54:38 UTC