Pex – Some Early Thoughts

February 2nd, 2010 by David Bending Leave a reply »

I've been looking recently at Pex, Microsoft's automated white box testing software. There's basically 4 parts to Pex:

  1. A framework for writing parameterised unit tests.
  2. An explorer, for finding boundary conditions in code.
  3. Suggestions of preconditions that should be added to methods.
  4. Moles – a way of stubbing even static properties and methods (such as DateTime.Now).

Parameterised Unit Tests (PUT)

When manually writing unit tests, we often end up with blocks of tests that are essentially the same in concept, but with different input/output combinations.  For example, an addition routine might have tests for different combination of negative and positive numbers.  Pex creates its tests a parameterized tests.  There is a template test, and underneath that an instance of each test value.

The templates are placed in a source file and look like normal unit tests.  The parameterised versions are stored underneath in a .g.cs file.  These files are not intended to be edited and are created automatically by the Pex explorer.

You can also write your own PUTs.  More on this later…

The Explorer

The 'white box' part of Pex refers to the explorer.  This essentially looks at all the possible paths through a piece of code and generates a test for each. Let's look at this piece of code:

public int Add(int x, int y)
{
    return x + y;
}

If we run Pex on this, we get the following test:

[TestMethod]
[PexGeneratedBy(typeof(CalculatorTest))]
public void Add01()
{
    int i;
    Calculator s0 = new Calculator();
    i = this.Add(s0, 0, 0);
    Assert.AreEqual<int>(0, i);
    Assert.IsNotNull((object)s0);
}

Actually there's a bit more to it – but this shows the basic details.  As we can see, it's a fairly dull test.  in particular Pex hasn't added any code to see if the result of the operation has overflowed. On the other hand let's see what it does if there's a bit more going on in the method:

public int Fibonacci(int n)
{
    if (n < 0)
    {
        throw new ArgumentOutOfRangeException("n");
    }

    if (n == 0)
    {
        return 0;
    }

    if (n == 1)
    {
        return 1;
    }

    return Fibonacci(n - 2) + Fibonacci(n - 1);
}

This is an (admiteddly rubbish) implementation of Fibonacci. It's more interesting that Add because there's more paths through it. This time when we run Pex we get:

[TestMethod]
[PexGeneratedBy(typeof(CalculatorTest))]
public void Fibonacci01()
{
    int i;
    Calculator s0 = new Calculator();
    i = this.Fibonacci(s0, 0);
    Assert.AreEqual<int>(0, i);
    Assert.IsNotNull((object)s0);
}

[TestMethod]
[PexGeneratedBy(typeof(CalculatorTest))]
public void Fibonacci02()
{
    int i;
    Calculator s0 = new Calculator();
    i = this.Fibonacci(s0, 1);
    Assert.AreEqual<int>(1, i);
    Assert.IsNotNull((object)s0);
}

[TestMethod]
[PexGeneratedBy(typeof(CalculatorTest))]
public void Fibonacci03()
{
    int i;
    Calculator s0 = new Calculator();
    i = this.Fibonacci(s0, 2);
    Assert.AreEqual<int>(1, i);
    Assert.IsNotNull((object)s0);
}

[TestMethod]
[PexGeneratedBy(typeof(CalculatorTest))]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void Fibonacci04()
{
    int i;
    Calculator s0 = new Calculator();
    i = this.Fibonacci(s0, int.MinValue);
}

[TestMethod]
[PexGeneratedBy(typeof(CalculatorTest))]
public void Fibonacci05()
{
    int i;
    Calculator s0 = new Calculator();
    i = this.Fibonacci(s0, 14);
    Assert.AreEqual<int>(377, i);
    Assert.IsNotNull((object)s0);
} 

So Pex has created a test case for each path through the program.

Suggestions

When passing reference types to a method, Pex will realise that the value could be null.  For all such methods it will suggest the a pre-condition is added.  There's also a button that will get Pex to automatically insert the pre-condition into the code for you.  This saves a bit of time, but isn't a huge win.  That said Pex does understand code contracts so there may be bigger wins to be had here.

Moles

Pex also contains a mocking framework called Moles.  Unlike most mocking frameworks, Moles do their work at runtime level (like Isolator) and consequently you can use them to mock static properties.  Consider this code:

public void Y2kBug()
{
    if (DateTime.Now == new DateTime(1999, 12, 31))
    {
        throw new InvalidProgramException("Arrgghhh!!!!");
    }
} 

We'd like to unit test this, and we don't want to have to change the system clock to do so.  Unfortunately, DateTime.Now is static so the likes of Rhino Mocks and MoQ can't help.  With Pex Moles we can do the following:

[TestMethod]
[ExpectedException(typeof(InvalidProgramException))]
[HostType("Moles")]
public void Y2kBugTest()
{
    MDateTime.NowGet = () => new DateTime(1999, 12, 31);

    Y2k target = new Y2k();
    target.Y2kBug();
} 

We have generated Moles for mscorlib (by choosing Add New Item -> Pex Moles) in Visual Studio.  This creates a mole for each mscorlib type in the Moles namespace with the M prefix.  We then tell the mole to return the value we ant in the unit test (note that we supply a delegate not a value, and that properties are a Put and a Get mole).  By specifying the HostType attribute for our test, we cause the unit test runner to route the code trhough a mole supplying the value we want.

See Nikolai Tellman's video for more on this at: http://channel9.msdn.com/posts/Peli/Moles-Replace-any-NET-method-with-a-delegate/.

 

Share
Advertisement
Celtic-Style Contemporary Jewellery and Gifts

1 comment

  1. Looks like you can write your own PUTs.  More on this later…

Leave a Reply