Thursday, September 18, 2008

In the previous post, we implemented the insertion method of a binary heap using Test Driven Development (TDD) and parameterized unit tests (I'll leave the full implementation of the insertion method as an exercise).

In this post, we will take a closer look at the development flow that we used and show how it relates to traditional TDD. For many people, combining TDD and automated test generation makes no sense. I believe this is not true anymore, and this is what this post is about.

Test Driven Development Flow

TDD has a well-defined flow where developers

  1. write a unit test,
  2. run the test and watch it fail,
  3. fix the code,
  4. run the test and watch the test pass. Start again (I'll skip refactoring in this discussion)

During this flow, practitioners also refer to the green state when all tests are passing and red state when some tests are failing. The little picture below depicts this little state machine.

tddstates

A key aspect of this approach is that the design of the API is inferred by writing the 'scenarios', i.e. tests. Therefore, unit tests are a critical building block of the TDD flow.

Note also that xUnit-like test frameworks (pick your favorite framework here) provide the automation tools so that the execution of the test and the investigation of a failure is painless for the programmer.

Test Driven Development Flow With Parameterized Unit Tests

Parameterized unit tests and Pex change the TDD flow while retaining its essence: building the design from tests. Here are the steps, we'll discuss them in detail later on:

  1. Write a parameterized unit test,
  2. Run Pex and watch some generated unit tests fail,
  3. Fix the code,
  4. Run Pex again,
    1. Some previously generated unit tests now pass, at least one new failing unit test get generated (go to 3)
    2. All generated tests are passing, start again (go to 1)

The key difference is the shortcut from step 4 (generating unit tests) to 3 (fix the code), without passing through step 1 (write a new test). This is illustrated by the yellow feedback loop in the diagram below:

 etddcycle

To the risk of repeating myself, let me emphasize some important points here:

  • you still need to write unit tests, it's just that they can have parameters: Pex generates unit tests from parameterized unit tests, by instantiating them. The person who writes the parameterized unit test is you, not the tool!
  • it is still about design: using parameterized unit tests is as much about design as closed (i.e. parameterless) unit tests. In fact, one can argue that parameterized unit tests are way closer to a specification that closed unit tests.
  • it is test first: in case it was not obvious by now :)

The shortcut from 4 to 3

As mentioned above, the main difference in the flow is that jump from running the tool (step 4) to fixing the code (step 3), without writing new tests (step 1). This happens because a parameterized unit tests captures equivalence classes rather than a single scenario like closed unit tests. As a result,

  • you spend more time fixing/implementing the code: the nice thing about the shortcut is that you can spend more time writing the code, rather than writing tests.
  • you can leverage automated white-box testing tools: Pex tries to get the maximum coverage out of your parameterized unit test (note remember that getting coverage also means covering the throwing branches in Assert), using an automated white-box code analysis. Now that you have also those manycore CPUs on your motherboard, you can finally make a good use of them :)

To Pex and not to Pex

An important aspect of parameterized unit tests (and tools like Pex) is that you do not have to drop (completely) your existing habits: in many cases, it is easier to write closed unit tests! In fact, you can always start from a closed unit test and refactor it later. We do not expect users to parameterized unit tests write exclusively (another nice read here), but when you do write them, we expect you'll get much more 'out of your buck'.

In future posts, we'll discuss different ways to write parameterized unit tests: from refactoring existing unit tests to using test patterns.

To be continued...

Next time, we'll go back to the heap and look at implementing the 'remove minimum' method...

(Pex is a automated structural testing tool from Microsoft Research. More information at http://research.microsoft.com/pex.)

posted on Thursday, September 18, 2008 7:15:26 AM UTC  #    Comments [6]
 Tuesday, September 09, 2008

The other day I stumbled on a first draft on a new book on algorithms (Data Structure and Algorithms). After taking a peak at the draft, I found some (hidden) motivation to finally write a decent binary heap for QuickGraph. A heap is a critical data structure for Dijkstra shortest path or Prim's minimum spanning tree algorithm, since it is used to build efficient priority queues.

In this post, we'll start building a binary heap using Test-Driven Development (write the tests first, etc...) and parameterized unit tests.

BinaryHeap?

The heap is a tree where each parent node has a value smaller or equal to the child nodes. The binary heap is a heap implemented through a binary tree, and to make things more interesting (and fast), the tree is usually mapped to an array using indexing magic:

  • parent node index: (index - 1) /2
  • left child node: 2*index + 1
  • right child node: 2*index + 2

The indexing magic is typically the kind of things that introduce bugs.

Let's write that first test

We start by writing a test that simply fills any binary heap with a number of entries. A possible test for this is written as follows:

[PexMethod]
public void Insert<TPriority, TValue>(
    [PexAssumeUnderTest]BinaryHeap<TPriority, TValue> target,
    [PexAssumeNotNull] KeyValuePair<TPriority, TValue>[] kvs)
{
    var count = target.Count;
    foreach (var kv in kvs) {
        target.Add(kv.Key, kv.Value);
        AssertInvariant<TPriority, TValue>(target);
    }
    Assert.IsTrue(count + kvs.Length == target.Count);
}

There are a number of unusual annotations in this test. Let's review all of them:

  • The test is generic: Pex supports generic unit tests. This is really convenient when testing a generic type.
  • PexAssumeUnderTest, PexAssumeNotNull: it basically tells Pex that we don't care about the case where kvs or target is null.
  • We've added a Add(TPriority priority, TValue value) method and Count property to the BinaryHeap

There are also two assertions in the test. Inlined in the loop, we check the invariant of the heap (AssertInvariant). We'll fill up this method as we go. At the end of the test, we check that the Count property.

BinaryHeap version #0

We start with a simple (broken) implementation that does nothing:

public class BinaryHeap<TPriority, TValue> {
    public void Add(TPriority priority, TValue value) { }
    public int Count { returnt 0; }
}

Now that the code compiles, we run Pex which quickly finds that a non-empty array breaks the count assertion.

image

BinaryHeap version #1

We have a failing test so let's fix the code by storing the items in a list:

public class BinaryHeap<TPriority, TValue> {
    List<KeyValuePair<TPriority, TValue>> items = new List<KeyValuePair<TPriority, TValue>>();
    public void Add(TPriority priority, TValue value) {
        this.items.Add(new KeyValuePair<TPriority, TValue>(priority, value));
    }
    public int Count {
        get { return this.items.Count; }
    }

We run Pex again and all the previous failing tests are now passing :)

image

There's a new object creation event that happened (bold events should be looked at). Remember that the test takes a binary heap as argument, well we probably need to tell Pex how to instantiate that class. In fact, this is exactly what happens when I click on the object creation button:

image

Pex tells me that it guessed how to create the binary heap instance and gives me the opportunity to save and edit the factory. The factory looks like this and get included automatically in the test project:

[PexFactoryClass]
public partial class BinaryHeapFactory {
    [PexFactoryMethod(typeof(BinaryHeap<int, int>))]
    public static BinaryHeap<int, int> Create() {
        BinaryHeap<int, int> binaryHeap = new BinaryHeap<int, int>();
        return binaryHeap;
    }
}

All our tests are passing, we can write the next test... but wait!

We have an invariant!

The nice thing about data structures is that they have fairly well defined invariants. These are very useful for testing!

In the case of the heap, we know that the parent node priority should always be less or equal to the priorities of both of his left and right children. Therefore, we can add a method to BinaryHeap that walks the array and checks this property on each node:

[Conditional("DEBUG")]
public void ObjectInvariant() {
    for (int index = 0; index < this.count; ++index) {
        var left = 2 * index + 1;
        Debug.Assert(left >= count || this.Less(index, left));
        var right = 2 * index + 2;
        Debug.Assert(right >= count || this.Less(index, right));
    }
}
private bool Less(int i, int j) { return false; }

Remember that AssertInvariant method, let's call ObjectInvariant in that method and run Pex again.

void AssertInvariant<TPriority,TValue>(BinaryHeap<TPriority,TValue> target) {
    target.ObjectInvariant();
}

Pex immediately finds an issue:

image

This assertion is due to our overly simplified implementation of Less, which always return false.

Fixing tests, and finding new failing tests

We have failing tests so it's time to fix the code again. Let's start fixing on the Less method by using a comparer:

readonly Comparison<TPriority> comparison =
    Comparer<TPriority>.Default.Compare;
private bool Less(int i, int j)
{
    return this.comparison(this.items[i].Key, this.items[j].Key) >= 0;
}

We run Pex and it comes back with the following tests:

image

Two interesting things happened here:

  • the previous failing test (with [0,0], [0,0]) was fixed by fixing Less
  • Pex found a new issue where the input array involves a small key (3584), then a larger key (4098). A correct heap implementation would have kept the smaller key at the first position.

The coolest part is we did not have to write any additional line of code to get to this point: Pex updated the previous tests and generated the new failure for us.

This is a new kind of flow that occurs when using Pex in TDD: a code update has fixed some issues but created new ones. We are still moving towards our goal but we did not have to pay the price of writing a new unit test.

In fact, to fulfill the invariant and make this test pass we will have to write a correct implementation of the Add method.... without writing a single additional line of test code :)

to be continued...

posted on Tuesday, September 09, 2008 12:39:35 PM UTC  #    Comments [1]
 Wednesday, August 27, 2008

Update: renamed project to YUnit to avoid clashing with other frameworks.

I've been playing with custom test types for team test lately and the result of this experiment is YUnit. A microscopic test framework that lets you write tests anywhere since it only uses the Conditional attribute. That's right, any public static parameterless method tagged with [Conditional("TEST")] becomes a test :)

If you've always dreamed of implementing your own custom test type, this sample could be helpful to you. Remember that this is only a sample and comes with no guarantees of support.

Sources and installer available at: http://code.msdn.microsoft.com/yunit.

 

posted on Wednesday, August 27, 2008 10:26:36 AM UTC  #    Comments [0]
 Tuesday, August 26, 2008

It's that time of the year where a little refresh of QuickGraph (http://www.codeplex.com/quickgraph) is needed.

What's new?

  • New API to add and remove vertices from the graphs
  • Important bug fixes in the shortest path algorithms (oops!)
  • Support for MSAGL ( http://research.microsoft.com/research/msagl/ )
  • QuickGraph.Data, provides data structures build graphs of databases (given a DataSet)
  • QuickGraph.Heap, provides data structure to build graphs of SOS managed memory dumps (more later)

Enjoy.

 

posted on Tuesday, August 26, 2008 11:11:35 PM UTC  #    Comments [0]
 Wednesday, August 06, 2008

Read on Nikolai's announcement on the latest drop of Pex.

posted on Thursday, August 07, 2008 1:06:59 AM UTC  #    Comments [0]
 Thursday, July 31, 2008

Alexander Nowak has started a blog post chronicle on Pex and already has 6 episodes to it!

  • Pex - test Case 5 (regular expressions)
  • Pex - test case 4 (strings and parameter validation)
  • Pex - Test case 3 (enums and business rules validation)
  • Pex - test case 2 
  • Pex - test case 1
  • Starting with Pex (Program Exploration)

    The posts give a nice point of view of Pex from a user perspective, and against classic testing techniques such as equivalence classes.

  • posted on Thursday, July 31, 2008 9:25:49 PM UTC  #    Comments [0]
     Wednesday, July 30, 2008

    Linear programming problems are usually solved using the simplex algorithm. While it is easy to encode a constraint system of linear equalities and inequalities as a Parameterized Unit Test for Pex, there is currently no way to tell Pex that we want test inputs that are “minimal” according to a custom objective function. However, Pex can still generate *surprising* feasible solutions.

    Let's start with a simple set of linear inequalities that define our problem.

    [PexMethod]
    public int Test(int x, int y)
    {
    // PexAssume is used to add 'constraints' on the input
    // in this case, we simply encode the inequalities in a boolean formula PexAssume.IsTrue( x + y < 10 & // using bitwise & to avoid introducing branches 5 * x + 2 * y > 20 & -x + 2 * y > 0 & x > 0 & y > 0);
    // the profit is returned so that it is automatically logged by Pex return x + 4 * y; }

    After running Pex, we get one feasible solution. It is not optimal as expected since we don't apply the simplex algorithm.

    image

    Enter overflows

    Remember that .Net arithmetic operations will silently overflow unless you execute them in a checked context? Let's push our luck and try to force an overflow by changing x > 0 constraint to x > 1000:

    [PexMethod]
    public int Test(int x, int y)
    {
        PexAssume.IsTrue(
            x + y < 10 &
            5 * x + 2 * y > 20 &
            -x + 2 * y > 0 &
            x > 1000 & y > 0
        );
        return x + 4 * y;
    }

    Z3, the constraint solver that Pex uses to compute new test inputs, uses bitvector arithmetic to find a surprising solution that fulfills all the inequalities (our profit has just gone of the roof :)).

    image 

    Z3 is truly an astonishing tool!

    Checked context

    In order to avoid overflow, one should use a checked context. Let's update the parameterized unit test:

    [PexMethod]
    public int Test(int x, int y)
    {
        checked
        {
            PexAssume.IsTrue(
                x + y < 10 &
                5 * x + 2 * y > 20 &
                -x + 2 * y > 0 &
                x > 0 & y > 0
            );
        }
        return x + 4 * y;
    }

    In fact, in that case, Pex generates 2 test cases. One test that passes and the other test that triggers an OverflowException (implicit branch).

    image

    Stay tuned for more surprising discoveries using Pex.

    posted on Wednesday, July 30, 2008 8:35:31 AM UTC  #    Comments [2]
     Thursday, July 03, 2008

    Brian Keller dropped by our offices to record a movie on Pex. A good old white board session to explain how pex works:

    http://channel9.msdn.com/posts/briankel/Pex-Automated-Exploratory-Testing-for-NET/

     

    posted on Friday, July 04, 2008 1:21:54 AM UTC  #    Comments [0]
     Tuesday, June 24, 2008

    We've added a little filter to Pex that flags potential testability issues in your source code (at least in the context of unit testing). The idea is simple: if your code logic branches over API that depends on the environment (file system, UI, network, time, etc...), you're not doing 'pure' unit testing anymore and it could be flagged as a testability issue.

    Why do we do this anyway?

    The problem is that Pex is very sensitive to those issues: it cannot control the environment. Let's take a look at a simple example where we write a custom stream class with a testability issue in one of the constructor:

    image

    The constructor checks that the file exists. In order to pass that point in the program, you would actually need to create or find an actual file in the file system. You're talking to the file system, this is already integration testing.

    Parameterized drama

    Let's be optimistic and write a parameterized unit test that reads a file:

    image

    Pex comes back with a single test, passing null as fileName (i.e. default(string)). Since Pex does not know how the file system works, it cannot create a valid file name, and that's where the story ends.

    image 

    Help is on the way

    To help you diagnose these issues, we've added specialized logging flags. Pex shows hints in the issue notification area:

    image

    Clicking on that event will give you additional important data: which API was called and the stacktrace at the time of the call :)

    image

    posted on Tuesday, June 24, 2008 1:08:33 PM UTC  #    Comments [0]
     Thursday, June 05, 2008

    Ever wonder what was happening inside the ResourceReader (where do those resources come from anyway!).... Check out Nikolai's post on using Pex to test this (complicated) class...

    posted on Thursday, June 05, 2008 9:17:06 AM UTC  #    Comments [0]
     Saturday, May 24, 2008

    If you're interrested on reading more about Pex, here are some online document that should get you satisfied:

    The tutorial contains hands-on labs and exercises to understand how Pex generates new test cases. Highly recommend if you're interrested on Pex.

    Happy reading!

    posted on Saturday, May 24, 2008 11:00:01 PM UTC  #    Comments [0]
     Thursday, May 22, 2008

    Nikolai broke the news; we've just released Pex 0.5... get it while it's hot!

    We're eager to hear some feedback, so don't hesitate to tell us what you think about it.

    posted on Thursday, May 22, 2008 11:30:00 PM UTC  #    Comments [11]
     Thursday, May 08, 2008
    posted on Thursday, May 08, 2008 10:40:27 PM UTC  #    Comments [2]
     Wednesday, February 27, 2008

    This is one problem for which we don't have an elegant solution yet:

    what is the best way to craft a name for a generated test?

    Let's see an example; given the following parameterized unit test,

    [PexMethod] void Test(int i) {
        if (i == 123) throw ArgumentException();
    }

    Pex would generate 2 tests: i = 0, i = 123. So it seems doable to infer test names such as

    [TestMethod] void Test0() { this.Test(0); }
    [TestMethod, EE(typeof(ArgumentException))]
    void Test123ThrowsArgumentException() { this.Test(123); }

    So what's so difficult about it? Well, most PUT's aren't that simple and as the size of the generated parameter increases, the methods might increase as well (strings getting bigger). Here's a list of potential problems:

    • the method should stay relatively small (less than 80 chars),
    • the parameters might be objects or classes, which do look well in a string format,
    • generated strings might be huge and contain weird unicode characters,
    • the tests might involve mock choices which again do not render well to strings,
    • the more parameters the more cryptic things become

    Our approach: Timestamps

    To the light of all those problems, we've taken the shortcut route in Pex by simply using combination of the parameterized unit test method signature and the timestamp when the test is generated:

    [TestMethod] void TestInt32_20080224_124301_35() { ... }

    This is ugly, how can I change that?

    We've added an extensibility point to support custom test naming scheme. After registering your 'namer', you will get opportunity to craft a test name following your favorite code standard. You will have the generated test, output, exception, etc... at your disposition to make an intelligent choice there.

    Off course, you're also welcome to drop a comment on this post to suggest a better scheme.

    posted on Wednesday, February 27, 2008 4:18:46 PM UTC  #    Comments [2]
     Saturday, February 23, 2008

    So how do you write negative test cases with Pex? Here's a nice solution I was working on. I'm wondering

    Traditional ExpectedExceptions style

    Let's test the constructor a type Foo that takes a reference argument. We expect to throw a ArgumentNullException when null is passed. Therefore, we could write

    [ExpectedException(typeof(ArgumentNullException))]
    void Test() {
         new Foo(null);
    }

    or using xUnit style assertions,

    void Test() {
         Assert.Throws(delegate { new Foo(null); });
    }

    Pex ExpectedExcetions style

    Let's refactor our first test and push 'null' as a test parameter. We add an assertion after the constructor to make sure a null parameter never succeeds.

    void Test(object input) {
        new Foo(input);
        Assert.IsNotNul(input); // we should never get here
    }

    The interesting part is that this test will not only test for the null value but also for the passing values as well. Moreover, there might be more checks over the input which might trigger other exceptions. In that case, additional asserts could be added -- or even better, centralized in an invariant method.

    So, what do you think?

    posted on Saturday, February 23, 2008 5:40:50 PM UTC  #    Comments [2]
     Saturday, February 16, 2008

    Looks like I've just made it in for the Seattle ALT.NET 'un'-conference :)

    posted on Sunday, February 17, 2008 7:02:01 AM UTC  #    Comments [0]
     Friday, February 15, 2008

    Some may wonder if there's any relation between my nickname 'Peli' and 'Pex': there's none! Pex just stands for "Program Exploration".

    In fact, Pex was started long before I joined the project by my colleague Nikolai Tillmann. Nikolai started the MUTT project (read this), which is the ancestor of Pex. He's the mastermind behind the IL rewriter, symbolic engine, and well a large part of Pex :) Hopefully, I'll convince him to start a blog :).

    posted on Saturday, February 16, 2008 2:43:55 AM UTC  #    Comments [0]
     Wednesday, February 13, 2008

    Maybe yes, maybe no, I guess it depends on the reviews... Have you reviewed it?

    http://submissions.agile2008.org/node/2766

    posted on Thursday, February 14, 2008 6:53:49 AM UTC  #    Comments [0]

    This is a general recommendation if you're planning to use a tool like Pex in the future: make sure that preconditions (i.e. parameter validation) fails in a different fashion that other assertions.

    Here's a snippet that shows the problem:

    // don't do this
    void Clone(ICloneable o) {
         Debug.Assert(o != null); // pre-condition
         ...
         object clone = o.Clone();
         Debug.Assert(clone); // assertion
    }

    Why is this bad?

    A tool like Pex will explore your code and try to trigger every Debug.Assert it finds on its way. When the assertion is a precondition, it is likely expected and one would like to emit a negative test case (i.e. 'expected exception').

    The problem in the snippet above is that both failure will yield to the same assertion exception and it will very difficult to *automatically* triage the failure as expected or not.

    How do I fix this?

    Make sure different classes of assertions can be differentiated automatically, through different exception types, tags in the message, etc...

    posted on Thursday, February 14, 2008 1:51:00 AM UTC  #    Comments [3]
     Friday, February 01, 2008

    The bus that rides from Redmond to Seattle now has an excellent WiFi/Internet support. It helps killing the time when traffic gets really bad... For example, I can look at my bus through the network of king county webcams :)

    posted on Friday, February 01, 2008 12:30:12 PM UTC  #    Comments [0]
     Saturday, December 22, 2007

    Scott swinged by MSR a couple weeks ago to talk about Pex.

    http://hanselminutes.com/default.aspx?showID=111

     

    posted on Saturday, December 22, 2007 8:02:30 PM UTC  #    Comments [0]
     Thursday, December 06, 2007

    Update: this talk has been cancelled.

    I'll be giving a talk about Pex in Diegem on January 3.

    http://msdnrss.thecoderblogs.com/2007/12/06/msdn-techtalk-dynamic-analysis-and-test-generation-for-net-with-pex/

    posted on Friday, December 07, 2007 12:33:33 AM UTC  #    Comments [0]
     Wednesday, December 05, 2007

    In the previous post, we went through the exploration testing process to exercise a simple method, CheckPositive. In this post, we'll try the same exploration testing, but will let Pex do it.

    // mehod under test
    1 void CheckPositive(int i, bool @throw) {
    2     if (i < 0) {      
    3          Console.WriteLine("not ok");
    4          if (@throw)
    5             throw new ArgumentException();
    6     }
    7     else
    8         Console.WriteLine("ok");
    9 }
    // hand-crafted unit tests
    [TestMethod] void Zero() {
         CheckPositive(0, false);
    }
    [TestMethod] void MinusOne() {
         CheckPositive(-1, false);
    }
    [TestMethod] void MinusOneAndThrow() {
         CheckPositive(-1, true);
    }

    Exploration testing with Pex

    To let Pex explore the CheckPositive, we write a little test wrapper around that method:

    [TestClass, PexClass]
    public partial class ExplorationTesting {
        [PexMethod]
        public void Test(int i, bool @throw) {
            CheckPositive(i, @throw);
        }

    We also instrumented the original method with additional methods to track down the path conditions that Pex computes along the execution traces. Pex generates 3 pairs of values which are equivalent to what the test we manually created:

    • 0, false
    • int.MinValue, false
    • int.MinValue, true (throws)
    posted on Thursday, December 06, 2007 12:54:15 AM UTC  #    Comments [1]
     Tuesday, December 04, 2007

    In the previous post, we clarified what Pex was not doing. So what does it do?

    Pex performs some kind of automated exploration testing. I'll dive deeper into the details of this, but let's start with an example that gives the high level idea of the methodology.

    Exploration Testing

    Let's start by doing some exploration testing on a simple method that checks that an integer is positive, CheckPositive:

    1 void CheckPositive(int i, bool @throw) {
    2     if (i < 0) {      
    3          Console.WriteLine("not ok");
    4          if (@throw)
    5             throw new ArgumentException();
    6     }
    7     else
    8         Console.WriteLine("ok");
    9 }

    One way to 'explore' this method would be to throw different values at CheckPositive and use the debugger to see what's happening.

    Iteration 1: pick the default

    Let's create a unit test that does exactly that and step into the debugger. Since we don't really know anything about CheckPositive yet, we simply pick 0 for i (actually default(int)).

    [TestMethod]
    void Zero() {
         CheckPositive(0, false);
    }

    When we reach the statement "Console.WriteLine..." on line 8, we can figure out that we took this branch because the condition "i < 0" on line 2 evaluated to false. Let's remember this and continue on.
              line 2, i < 0 == false, uncovered branch

    The execution continues and the test finished successfully.

    Iteration 2: flip the last condition

    In the previous run, we've remembered that some code was not covered on line 3. We also know that this code path was not covered because the condition "i < 0" evaluated to false. At this point, we usually intuitively figure out a value of 'i' in our brain, to make this condition true. In this case, we need to solve "find i such that i < 0". Let's pick -1.

    [TestMethod]
    void MinusOne() {
         CheckPositive(-1, false);
    }

    We run the test under the debugger. As expected on line 2, the condition evaluates to true, and the program takes the other branch that in the previous test.
    The program continues and reaches line 4 where another if statement branch. Since the condition  "@throw" evaluates to false, we take the branch that throws and remember the condition:
              line 4, @throw == false, uncovered branch

    The program continues to run and finishes.

    Iteration 3: path condition + flipped condition

    We've still some uncovered branch to cover in the method, 'guarded' by the condition at line 4. To be able to cover this code, we need 2 things:
          1) reach line 4: i < 0
          2) make the condition in line 4 evaluate to true: @throw == true

    So to cover the last statement in the method, we need to find parameter values such that
                      i < 0 && @throw == true

    Let's pick -1, and true.

    [TestMethod]
    void MinusOneAndThrow() {
         CheckPositive(-1, true);
    }

    The test executes and now throws an exception as we wanted. At this point, we've fully covered to behavior of CheckPositive.

    What about Pex?

    Pex uses the same 'exploration' methodology as above. Pex executes a parameterized unit tests over and over and tries to cover each branch of the program. As it executes more code, it learns about new branches to cover etc... To find the input, Pex uses a constraint solver, Z3.

    posted on Wednesday, December 05, 2007 3:17:38 AM UTC  #    Comments [2]

    Nikolai Tillmann published a paper on DySy, a tool that can infer likely invariants by monitoring the code that is running.

    DySy is was built on top of the infrastructure that Pex uses to generate test cases. In fact, it is one of our sample application :)

    posted on Wednesday, December 05, 2007 12:53:17 AM UTC  #    Comments [0]
     Friday, November 30, 2007

    I realized that I had not talked much about how Pex computes the values for the test parameters... the most important part of the tool!

    It's not ...

    Let's start by getting to wrong ideas out of the way. Parameterized tests are nothing new, they exist in MbUnit, VSTS, XUnit.Net, FIT, etc... so what's different with Pex?

    • it is not random: when it comes to generate data, the easiest solution is to plugin a random generator. If the state space is big enough (e.g. integers 2^32), it highly unlikely that random tests will find the interesting corner cases,

    if (i == 123456)
         throw new Exception(); <---------- random won't find this

    • it does not require ranges or hints for the data: Pex does not require annotation to specify the range of particular inputs. All the relevant input values are inferred from the code itself (we'll see later how).
    • it is not pairwize testing: following the comment above, Pex does use a pairwize approach.
    • it is not data testing: data testing such as FIT or MbUnit RowTest usually consists of rows containing a set of inputs and the expected output. In Pex, you cannot provide the expected output as a 'concrete' value, you need to express it as code (through assertions for example). This is a subtle difference that radically changes the way you write your tests.

    [RowTest, Row(0, 1, 1), Row(1, 0, 1)] // data test for the addition
    void AddTest(int a, int b, int result)
    {   Assert.AreEqual(result, a + b);  }

    [PexMethod] // 0 is the neutral of the addition operation
    void ZeroNeutralTest(int b)
    {   Assert.AreEqual(b, 0 + b);  }

    • it is not a static analysis tool: Pex does a dynamic analysis of the code; it analyses the code that *is* running. Pex does this by rewriting the IL before it's jitted and instrumenting it with (many) callbacks to track precisely which IL instruction is being run by the CLR. So yes, Pex analyses the IL but on the fly rather than 'statically'.

    Ok, now we've got a better idea of what Pex is not. So how does it work? ....

    posted on Friday, November 30, 2007 5:19:05 PM UTC  #    Comments [3]
     Friday, October 19, 2007

    In it's Weekly Source Code, Scott Hanselman presents a new CodePlex project, NDepend.Helpers.FileDirectoryPath from Patrick Smacchia. Nice, better path handling should have been part of the BCL a while ago. 

    Path stuff is hard

    Path normalization and parsing is not an easy task so when Patrick Smacchia mentions that his code "100% unit-tested", I decided to see if Pex could not find a little bug over there.

    A dumb parameterized unit test

    So I added wrote the following parameterized unit test, which 'simply' calls the constructor of FilePathRelative. Under the hood, there is some string manipulation done by the library to normalize the path, it should be interresting to see what comes out of this. I also added calls to PexComment.XXX to log the input/output values (Pex will build a table out of this):

        [PexMethod]
        public void FilePathRelativeCtor(string path) {
            PexComment.Parameters(path);
            FilePath result = new FilePathRelative(path);
            PexComment.Value("result", result.FileName);
        }

    Ooops

    So Pex starts running and soon enough an assert pops up. Pex had just found a neat little path that broke an assertion in the library:

    [Test]
    public void FilePathRelativeCtor_String_71019_003302_0_05() {
        this.FilePathRelativeCtor("/");
    }

    Popping up the reports, I went for the parameter table (remember the PexComment calls) that shows one row for each generated test. In fact, the 5-th test that Pex generated was triggering the assert:

    Note that "//" also triggers the bug which seems to indicate that any path finishing by "/" will have this behavior.

    The path condition

    Lastly, I took a quick look at the path condition that Pex solved to discover the bug (see red below). Luckily this one is fairly easy and one can clearly see 'path[0] == '/' in there.

     What did we learn today?

    Handling paths is hard :)

    Also, we saw that a dumb parameterized unit test (just calling a ctor), could find a bugs. If you use assertions, it will help Pex look for bugs in your code.

    posted on Friday, October 19, 2007 3:46:37 PM UTC  #    Comments [3]
     Wednesday, October 17, 2007

    Update: I will not be at the Seattle Code Camp, too much rescheduling.

    I'll be presenting Pex at the Seattle Code Camp in Nov.

    Pex – Automated White Box Unit Testing

    Parameterized unit testing is becoming a mainstream feature of most unit test frameworks; MbUnit RowTest (and more), VSTS data tests, xUnit.net Theories, etc... Unfortunately, it is still the responsibility of the developer to figure out relevant parameter values to exercise the code. With Pex, this is no longer true. Pex is a unit test framework addin that can generate relevant parameter values for parameterized unit tests. Pex uses an automated white box analysis (i.e. it monitors the code execution at runtime) to systematically explore every branches in the code. In this talk, Peli will give an overview of the technology behind Pex (with juicy low-level .NET profiling goodness), then quickly jump to exiting live demos.

    posted on Wednesday, October 17, 2007 8:36:52 AM UTC  #    Comments [0]
     Thursday, October 11, 2007

    When someone is writing a book that contains code snippets, the question of (automatically) keeping those in sync quickly becomes very imporant. There's already lots of different solutions to this problem (every author has probably it's own), here's yet another one for C# that we've developed to author the Pex documentation.

    Goals

    A couple things that we wanted to acheive with this tool:

    • snippets are always compilable and run as expected,
    • snippets can be full classes, methods or even partial statements
    • simple :)

    '#region' based solution

    This solution uses the #region directive to define a snippet. The region describe contains the snippet name, which will be used to dump it into a file. For example, given this piece of C#,

    ...
    #region snippet StackExamplePart3
    stack.Push(new object);
    #endregion
    ...

    Our parse will extract the code in the region and write it to StackExamplePart3.tex, which gets pulled in our LaTeX scripts.

    \begin{verbatim}
    stack.Push(new object);
    \end{verbatim}

    That's it?

    Yes, you can author snippets that stay compilable and up to date:

    • we can author all the snippets in Visual Studio and we are sure they always compile
    • it's very easy to parse the #region's (left as exercise ;))
    • #region are very flexible in terms what they contain so we can have snippets containing partial methods, statement, etc...
    • the scheme aslo supports nested regions which is usefull when one explains an example line by line, and integrate the entire sample at the end. For example, DeclaringUnitTest is a 'sub'-snippet of UnitTest:
    #region snippet UnitTest
    #region snippet DeclaringUnitTest
    [TestMethod]
    void Test(int i)
    #endregion
    {
       
    }
    #endregion
    • we can integrate our snippets in unit tests and verify they work as expected
    • the tool can be integrated into the build process as a post-command build

     

    posted on Thursday, October 11, 2007 1:41:32 PM UTC  #    Comments [2]
     Sunday, September 30, 2007

    In Pex, we have our own version of all (and more) collection classes from the BCL. This duplication may sound stupid but there's a very good reason behind it: since Pex instruments code (i.e. rewrites IL), the BCL collections might be instrumented as well... leading to a poorer performance (instrumented code is slower for many reasons). Therefore, to avoid this situation, we ended up using our own implementation which never gets instrumented.

    While using our collections, we added 2 features that we like a lot: readonly interfaces and small collections.

    Readonly interfaces

    Readonly interfaces are handy to 'safely' expose collections, once you start using them you get hooked:

    • ICountable<T>, a readonly enumerable with a Count.
    interface ICountable<T> : IEnumerable<T>
    {
        int Count {get;}
    }
    • ICopyable<T>, a countable that can be copied around,
    interface ICopyable<T> : ICountable<T>
    {
        void CopyTo(T[] array, int index);
    }
    • IIndexable<T>, a indexed collection
    interface IIndexable<T> :  ICopyable<T>
    {
        T this[int index] { get; }
    }

    We also have a couple more interfaces for dictionary style collections but you get the idea.

    Small Collections

    Small collections are optimized collections with 0, 1 or 2 elements. Depending on your scenario, these can improve the performance of your application while lowering the pressure on the GC (create less objects -> less stuff to garbage collect). If you create a lot of objects which each have collections, ask yourself: are you lazy allocating the collections? what should be the initial size of the collection? do you expect more than one element on average?

    posted on Sunday, September 30, 2007 1:33:15 PM UTC  #    Comments [0]
     Sunday, September 23, 2007

    xUnit, the new variation on the 'unit test framework' theme comes with support for data driven tests: 'Theories' (funny name by btw). Pex is a plugin for test frameworks, so we've added support for xUnit as well.

    [PexClass] // xUnit does not have fixture attributes
    public class MyTests
    {
        [Theory, DataViaXXXX] // xUnit theories
        [PexTest] // let pex help you 
        public void Test(int a, ....)
        {}
    }

    posted on Sunday, September 23, 2007 11:26:32 PM UTC  #    Comments [0]