Click here to Skip to main content
15,886,518 members
Articles / All Topics

Making your Unit-tests Readable

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
18 Jan 2014CPOL3 min read 5.8K   1  
How to make your unit tests readable with StoryQ

Introduction

I don't know how about you, but I'm a great fan of TDD. Seriously, I find it to be one of the best practices I have in my toolbox. Nevertheless it has some limitations.

TDD does a great job for you if you are a developer. It focuses on the low level allowing to simulate any possible situation in any given component. It keeps your brain busy working out the best ways to write the system in a testable fashion making use of the good design patterns and practices. Another important feature - protects you from over-engineering by setting the scope early - implement just enough to make the tests pass and nothing else. Not to say that you get the tests automation for almost free. That's all well known and cool, except for the last thing.

I've witnessed it many times that even though you've done a great job applying TDD, it is useless for anyone other than programmers. Unit-tests are all about the low level components in isolation. They cannot be read by non-devs. Understanding the component structure is also tricky. OOP was supposed to simplify things by making programs talk in the domain terms and UML would visualise it. This seemed to be a great idea in the past, but looks like we are getting dumber or OOP and UML do not actually solve the problem.

Anyway, what I was seeing on my previous projects is that even though we had great number of tests and a decent coverage, this was useless for our quality control and the QA folks were doing their own testing often duplicating the effort since they could not use and control the product of the TDD. It's just in the wrong format. Even I do struggle understanding some tests after a couple of months.

BDD brings the two worlds closer together, but it's not a replacement for TDD, it's just a level on top of it. See the Test Automation Pyramid.

As there is more control introduced over the software testing these days in my industry, I don't find it wise to discard the valuable information. So I started looking around to make my tests more readable.

Before that, I was giving my test cases three component names - UnitOfWork_Context_Outcome. Example:

C#
class CalcTest
{
  public void Add_2and2_ShouldReturn4()
  {
    var calc = new Calc();

    var result = calc.Add(2, 2);

    Assert.That(result, Is.EqualTo(4));
  }
}

Unfortunately, the last two can become quite verbose if you have more than one assertion of a complicated context setup. Keeping them short makes you lose the details and end up with too generic phrases.

After having some good time applying BDD with SpecFlow, I fell in love with the Gherkin Given-When-Then syntax. Literally, the three component test case name is the same. I tried using SpecFlow for unit-tests but it wasn't that nice. Productivity went down. Additional steps were needed to generate the steps from text and regenerate them after rephrasing - as the result more time lost.

So I was actually wanting something C#-pish with a bit Gherkin flavour. After asking some collegues and Googling for a while, I've figured out the best option for me - the StoryQ. I also decided to switch to FluentAssertions from Nunit Assert.That(). It forms better messages which in combination with StoryQ brings awesome results!

Here are some samples from the StoryQ:

C#
using StoryQ;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace StoryQ.Demo
{
    [TestClass]
    public class DemoTest
    {

        [TestMethod]
        public void PassingExample()
        {
            new Story("Data Safety").Tag("sprint 1")
                .InOrderTo("Keep my data safe")
                .AsA("User")
                .IWant("All credit card numbers to be encrypted")
                .WithScenario("submitting shopping cart")
                  .Given(IHaveTypedMyCreditCardNumberIntoTheCheckoutPage)
                  .When(IClickThe_Button, "Buy")
                    .And(TheBrowserPostsMyCreditCardNumberOverTheInternet)
                  .Then(TheForm_BePostedOverHttps, true)

                  .ExecuteWithReport(MethodBase.GetCurrentMethod());
        }

The output is as follows:

Story is Data Safety => (#sprint 1)
  In order to Keep my data safe
  As a User
  I want All credit card numbers to be encrypted

      With scenario submitting shopping cart
        Given I have typed my credit card number into the checkout page => Passed
        When I click the Buy button                                     => Passed
          And the browser posts my credit card number over the internet => Passed
        Then the form should be posted over https                       => Passed

Meaningful tests and the output, what a joy!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --