Pex - Automated Whitebox Testing for .NET : Explorables

Explorables


Pex can reliably create values of all primitive types, arrays, and types with visible default constructors if all of their fields are visible. However, if an object must be created by calling a constructor or factory method that takes parameters, then Pex needs more information. (This way, Pex can even use types that are not visible.) In particular, Pex needs to know which constructor or factory method it should explore.

In general, a constructor might involve some control flow (parameter checking) or invoking different methods. Therefore, Pex needs to explore the constructor in addition to the actual test code. Types with constructors that involve control flow are called explorable because they need to be 'explored' in order to obtain interesting objects.

A classic example


Let's consider the following Account class; it has a money field which is not visible from the public context. In fact, the value of money is computed in the constructor of Account:

public class Account {
    private float money;
    public Account(Bank bank, string name) {
        // control-flow in the constructor
        if (bank == null) throw new ArgumentNullException();
        if (name == null) throw new ArgumentNullException();
 
        // calls to other method
        this.money = bank.GetMoney(name);
    }
 
    public float Money { 
      get { return this.money; }
    }
}

We want to write a test that states that for any valid instance of Account, the value of money should be positive. With Pex, we can pass an Account instance as a test parameter:

// test that needs an instance of Account
[PexMethod]
public void NeedsAccount(Account a)  {
    Assert.IsTrue(a.Money >= 0);
}

To explore this test, Pex will need to create valid instances of Account. Since the state of Account cannot be set entirely from public fields, Pex needs to pick a constructor or a static method (or a sequence of constructor, methods, properties, etc...) to 'set' the state of Account to the value it has computed.

While Pex makes a smart guesses, you can configure yourself how Pex should create an instance of a type. (And configuring how to create a type yourself is the only way to suppress Pex' notifications about its guesses.)

// binding
[assembly: PexExplorableFromConstructor(typeof(Account), typeof(Bank), typeof(string))]

  • Using a method factory:
// load any factories from this assembly
[assembly: PexExplorableFromFactories]
...
// this type contains factories
[PexClassFactory]
public static class AccountFactory {
    // this is a factory that creates 'Account' instances
    [PexMethodFactory(typeof(Account))]
    public static Account Create(Bank bank, string name) {
       return new Account(bank, name);
    }
}

Attributes


Pex comes with the following set of derived attributes:

Restrictions


  • Pex will not explore all code paths of the constructor. In particular, it will suppress paths that throw an exception in the constructor. Therefore, separate parameterized tests should be written to exercise the constructor.
  • If another object is required by the constructor, Pex will first try to create that object, whose constructor might need another object, and so on.

See also


Creatables
(c) Microsoft Corporation. All rights reserved. pex Wiki Documentation 0.93.50813.0