Saturday, June 30, 2007

In Pex, we added the possibility to specify the type under test of a given fixture:

public class Account {...}


[TestFixture, PexClass(typeof(Account))]
public class AccountTest {...}  

That's nice but why would it be useful... Beyond the fact that it clearly expresses the 'target' of the fixture, this kind of information can be leverage by tools like Pex.

For example, since we know that Account is the type under test, we can tune Pex to prioritize the exploration of the Account type.

Another interesting side effect is the targeted code coverage data. Instead of getting coverage information over the entire assembly, we can directly provide coverage over the type under test: the AccountTest covered xx% of Account.

Still toying around the concept, one can add a special filtering mode to the command line to execute all tests that target 'Account':

pex.exe /type-under-test:Account Bank.Tests.dll
posted on Saturday, June 30, 2007 2:23:24 PM UTC  #    Comments [0]
 Sunday, June 03, 2007

A nice side effect of the Pex infrastructure is that it computes coverage data while exploring a parameterized test. What does this mean to the user? Well, what about this specifying that a parameterized test should reach 100% coverage**:

[PexTest]
[PexExpectedCoverage(100)] // expect 100% coverage
public void UberTest(int i)
{ ... }
** What kind of coverage are we talking about?

Pex internally tracks implicit branch coverage (which can never be covered :)). So we usually refer to basic block coverage. By default, the coverage is reported for the code that was run by the parameterized test. This is a very important difference with usual coverage tools, which give numbers for the entire assembly.

posted on Sunday, June 03, 2007 12:24:56 PM UTC  #    Comments [0]
 Saturday, June 02, 2007

This post gives a little introduction on the integrated mock support in Pex (it should also make clear why we couldn't reuse existing (and excellent) mock framework).

As other frameworks, Pex support mocking interfaces or virtual methods in non sealed classes.

Choose and replay

Pex Mocks have 2 modes of execution that are quite different:

  • when Pex is looking for new input, they act as a source of parameter choices, (this will be clearer in the example below).
  • when executing the generated unit tests, they act as stubs.
Micro example

Let us illustrate this by mocking a simple interface that returns the name of an instance:

interface INamed
{
    string GetName();
}
Writing the mock

The mock for this interface looks as follows:

[PexMock] // specifies to pex that this type is a mock
public class MNamed : INamed
{
    public string GetName()
    {
        IPexMethodCallOracle call = PexOracle.MethodCall(this);
        // let's ask Pex for a name    
        return call.ChooseResult<string>(); 
    }
}

So what did we do really: The mock implementation of GetName fetches a value oracle,  an interface from which new values can be queried:

IPexMethodCallOracle call = PexOracle.MethodCall(this); 

Then, this oracle can be used to choose new values. It's like adding parameters to the test, but not through the test signature. In this case, we ask Pex to get a new result value. Pex will choose that value as if it was a parameter of the test:

return call.ChooseResult<string>();
Let's try it!

The following test takes a INamed instance (which we assumed to be non-null) and displays a message on the console if the name is equal to'Marc':

[PexTest]
public void GetName(INamed name)
{
    if (name.GetName() == "Marc")
        Console.WriteLine("hello marc");
}
Generated tests

Pex generates 2 unit tests that fully covers the code of method: Pex tracked the data returned by ChooseResult and computed that this value had to be equal to "Marc" to hit a different path in the execution.

The first test has GetName return a default value. The second generated test is more interresting as it shows how Pex sets up the behavior of the replay stub:

// test 2
MockTest.MNamed mn0 = new MockTest.MNamed();
IPexOracleRecorder oracle = PexOracle.NewTest();
oracle.OnCall(0, typeof(MockTest.MNamed), "GetName")
      .Returns("Marc");
this.GetName(mn0);

The oracle instance is used to set up the result value on the first call to GetName:

// on the call '0' to the method GetName of MockType.MNamed,
oracle.OnCall(0, typeof(MockTest.MNamed), "GetName")
      // return "Marc"
      .Returns("Marc");
Adding behavior

Behavior can simply be added to mock as code since Pex will explore the mock code as well. For example, let's refine the MNamed implementation to always return the same name:

[PexMock] // specifies to pex that this type is a mock
public class MNamed : INamed
{
    private string name;
    public string GetName()
    {
        if(this.name == null)
            this.name = PexOracle.MethodCall(this)
                              .ChooseNotNull<string>("name");
        return this.name;
    }
}
Wrapping Up

In this post, we've given a brief glimpse at the pex oracles. These are a special breed of mocks specific to Pex.

posted on Saturday, June 02, 2007 2:00:50 PM UTC  #    Comments [0]