Wednesday, February 13, 2008

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]
 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]
 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 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]
 Saturday, September 08, 2007

In a previous, we were looking at partial trust the lack of support for it. In this post, I'll show the key 'fixes' that we did to make Pex 'partial trust' aware.

Simulating Partial Trust

The easiest way to run under partial trust is to run your .net application from the network. However, in the context of a test framework, this would not work since many required permissions would not be granted (reflection, i/o, etc...). So we need a new AppDomain whose security policy considers the test framework assemblies as fully trusted.

  • Get a new AppDomain:
string trust = "LocalIntranet";
AppDomain domain = AppDomain.CreateAppDomain(trust);
  • Load the named permission set
PermissionSet permission = GetNamedPermissionSet(trust);
  • Create the code group structure that associate the partial trust permission to any code
UnionCodeGroup code= new UnionCodeGroup(
    new AllMembershipCondition(),
    new PolicyStatement(permission, PolicyStatementAttribute.Nothing));
  • give full trust to each test framework assembly:
StrongName strongName = CreateStrongName(typeof(TestFixtureAttribute).Assembly);
PermissionSet fullTrust = new PermissionSet(PermissionState.Unrestricted);
UnionCodeGroup fullTrustCode = new UnionCodeGroup(
new StrongNameMembershipCondition(strongName.PublicKey, strongName.Name, strongName.Version),
new PolicyStatement(fullTrust, PolicyStatementAttribute.Nothing));
code.AddChild(fullTrustCode);
  • Assign the policy to the AppDomain
PolicyLevel policy = PolicyLevel.CreateAppDomainLevel();
policy.RootCodeGroup = code;
domain.SetAppDomainPolicy(policy);

This is basically it (the rest of the details are left as an exercise :)).

Let them call you

Make sure to add the AllowPartiallyTrustedCallers to the test framework assembly otherwize users won't be allowed to call into it...

A twist...

Pex is bit invasive when it comes to partial trust. Pex rewrites the IL at runtime and turns all method bodies into... unsafe code (that is unverifiable). At this point, any will not run because of the SkipVerification permission.

No problemo, just add it to the permissionset:

permission.AddPermission(
    new SecurityPermission(SecurityPermissionFlag.SkipVerification)
    );

 

posted on Saturday, September 08, 2007 1:39:22 PM UTC  #    Comments [0]
 Thursday, August 23, 2007

A common requirement for unit test framework is the ability to test internal types.

That's easy! use InternalsVisibleToAttribute

With .Net 2.0 and up, this is a fairly easy task thanks to the InternalsVisibleToAttribute: add it to the product assembly to give 'visibility rights' to the test assembly.

// in assembly Foo
internal class Foo {}
// giving visibility rights to the Foo.Tests assembly
[assembly:InternalsVisibleTo("Foo.Tests")]

On the test assembly side, this works because unit test are 'closed' methods which do not expose any internal types.


[Test]
public void FooTest() {
    Foo foo = new Foo(); // we're using the internal type Foo
                         // but it's hidden in the unit test
}

What about parameterized tests? Make them internal as well

If one of the parameters of the test is internal, the test method will have to be internal as well in order to compile:

[PexTest]
internal void FooTest(Foo foo) {
   ...
}

Not pretty but still gets the job done. Pex will generate public unit test methods that invoke the internal parameterized test method, and we'll be happy:

[Test]
public void FooTest_12345() {
    this.FooTest(null);
}

What about MbUnit RowTest?

This issue was never faced by MbUnit RowTest because it only accepts intrinsic types such as int, long, etc... Those types are obviously public :)

posted on Friday, August 24, 2007 12:24:08 AM UTC  #    Comments [0]
 Saturday, July 14, 2007

Pex can analyze regular expressions*** and generate strings that matches them automatically!

What does it mean? Well, maybe, somewhere deep in your code your are validating some string with a regex (for example a url). In order to test the validation code, one needs to craft inputs that does not match (easy) and matches (harder) the regex.

Let Pex do it:

So what if Pex could be smart enough to understand a regex and craft inputs accordingly? In the example below, it would be very hard for a random generate to generate a string that matches the regex.

[PexTest]
public void Url([PexAssumeIsNotNull]string s)
{
    if (Regex.IsMatch(s, "(?<Protocol>\w+):\/\/(?<Domain>[\w@][\w.:@]+)\/?[\w\.?=%&=\-@/$,]*"))
        throw new PexCoverThisException(); // random won't find this
}

"" would be a failing match and foo://foo.com a good match. (To generate the correct match, my brain simulated the regex automaton and estimated one possible path). Interestingly, Pex generates....

Ā://Āā

Pretty ugly... but correct! This reminds us that while regex are used to validate input, what they'll let through is sometimes scary.

Compiled Regex + Pex = Love

The great part about supporting the regular expressions is that it comes for free (almost) since Regex can be compiled to IL in .Net. When the BCL generates the regex IL code, it effectily builds the automaton... which can be analyzed by Pex!!!

Refresher: Pex works analyzing the MSIL being executed.

Hey but not all Regex are compiled!

That's true. Compiling the regex is optional so Pex needs to do a little bit of 'plumbing' to make sure all regular expressions are compiled. This is simply done by substituting the real .ctor of the Regex class with a customized version that compiles the regex. I'll talk about substitutions deeper in the future.

*** Of course, the bigger the regex is, the harder it is going to be for Pex to craft a successful match.

posted on Sunday, July 15, 2007 4:49:53 AM UTC  #    Comments [1]
 Wednesday, July 04, 2007

One of the problem with Pex is that.... it's yet another dependency in your test project. Pex has it's own attributes which makes it very difficult to 'strip it out' of the test source. Many teams won't allow to check-in assemblies, they won't install external components on the build machine and just forget about touching the source code!

So how do you strip Pex?

In "Condition" lies the answer

An elegant solution uses a bit of Reflection, CodeDom and the MSBuild Condition attribute: generate Attribute stubs (shadows) and bind them to the project.

Pex modifies the project file and uses MSBuild conditions to conditionally include files and assembly references in the generated test project.

  • A boolean property PexShadows to controls the shadowing state: true if shadowed, false or missing otherwize.
<Project DefaultTargets="Build" ...>
  <PropertyGroup>
    ...
    <PexShadows>true</PexShadows>
  </PropertyGroup>
  • a conditional reference to Microsoft.Pex.Framework:
    <Reference 
        Include="Microsoft.Pex.Framework" 
        Condition="$(PexShadows) != 'true'" />

when the property PexShadows evalutes to true, the Microsoft.Pex.Framework assembly is not referenced anymore.

  • a file containing all the custom attributes 'stubs' (for all attributes in the Microsoft.Pex.Framework) is generated (automatically of course :)). Pex also dumps the source of several other helper classes. Each generated file is added to the test project conditionally:
    <Compile Include="Properties\PexAttributes.cs" Condition="$(PexShadows) == 'true'">
      <AutoGen>True</AutoGen>
      <DependentUpon>AssemblyInfo.cs</DependentUpon>
    </Compile>

That's it! Flip the value of PexShadows to bind/unbing your test project from Pex.

So what does Visual Studio says ?

Visual Studio is totally fooled by the maneuver. It shows the conditional files and references as if nothing happened. Add a menu item in the project context menu to switch it on and off and we are good to go :)

posted on Wednesday, July 04, 2007 12:28:12 PM UTC  #    Comments [0]
 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]
 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]
 Sunday, May 27, 2007

.Net 2.0 has been out for a while and it seems that 'generics' have not made it into unit test frameworks (that I know of). When I write unit tests for generics, I don't want to have to instantiate them!

For example, if I have an generic interface,

interface IFoo<T> {...}

then I'd really like to write this kind of test and let the test framework figure out an interresting instantiation (i.e. choice of T):

[Test]
public void Test<T>(IFoo<T> foo) { ... }

In the example above, System.Object can be trivially used to instantiate IFoo<T>. Of course, things get more interresting when mixing type argument, method argument and constraints :)

interface IFoo<T>
{
    R Bar<R>(T t)
     where R : IEnumerable<T>
}

In Pex, we've started to look at this problem... stay tuned.

posted on Sunday, May 27, 2007 1:09:00 PM UTC  #    Comments [3]
 Friday, April 20, 2007

With parameterized unit tests, it is not uncommon to generate a large number of exceptions. An basic exception log usually looks like this: a small message and the stack trace.

Whith this kind of output, a lot of work is still left to the user since he has, *for each frame*,  to manually open the source file and move to the line refered by the trace.

Give me the source context!

In the Pex reports we added a couple lines of code to read the source for each frame and display it in the reports (no rocket science). The cool thing is that you now can get a pretty good idea of what happened without leaving the test report. Multiply that by dozens of exceptions and you've won a loooot of time.

Here are some screenshots to illustrate this: an exception was thrown in some arcane method. The error message is not really useful (as usual).

If we expand the source and actually see the code, things become much clearer...

posted on Friday, April 20, 2007 7:12:40 AM UTC  #    Comments [0]
 Wednesday, April 11, 2007

MbUnit supports different flavors of parameterized unit tests: RowTest, CombinatorialTest, etc... If you are already using those features, it would be very easy for you to 'pexify' them:

namespace MyTest
{
     using MbUnit.Framework;
     using Microsoft.Pex.Framework;

     [TestFixture, PexClass]
     public partial class MyTestFixture
{
[RowTest]
[Row("a", "b")]
[PexTest]

public void Test(string a, string b)
{
...
}


}
}

Isn't this nice? :)

Some little notes:

  • 'partial' is helpfull to emit the generated unit test in the same class... but not the same file. Pex also support another mode where partial is not required.
  • the Pex attributes do not 'interfere' with the MbUnit ones. Your unit tests will still run exactly the same with MbUnit.
posted on Wednesday, April 11, 2007 11:47:27 AM UTC  #    Comments [2]
 Sunday, April 01, 2007

This is the first post about Pex and how to use it. Since Pex is a fairly large project, I'll probably stretch the content of a large number of entries. Stay tunned...

Pex gives you Parameterized Unit Tests

Data-driven tests are not something new. They exist under different forms such as MbUnit's RowTest or CombinatorialTest, VSTS's DataSource, etc... So what's so special about Pex? The major difference is that Pex finds the parameter inputs for you (and generates a unit test out of it).

Whereas the user had to (smartly) guess a set of input for the data-driven tests, Pex tries to compute the relevant inputs to those tests automatically (and may also suggest fixes).

Note: The way Pex finds the input will be covered in more details later. In a couple words, Pex performs a systematic white box analysis of the program behavior. It tries to generate a minimal test suite with maximum coverage.

Parameterized Unit Tests, what does it feel like?

Parameterized unit tests are methods with parameters. There's nothing magic about that. Pex provides a set of custom attributes so that you can author them side-by-side with classic unit tests:

[TestClass, PexClass] // VSTS fixture containing parameterized tests
public class AccountTest
{
    // parameterized unit test
    // account money should never be negative, for any 'money', 'withdraw'
    [PexTest]
    public void TransferFunds(int money, int withdraw) {...}
}

When Pex finds interresting data to feed the parameterized unit test, it generates a unit test method that calls the parameterized unit test. This also means that once the unit test has been generated, you do not need Pex anymore to run the repro.

[TestClass, PexClass] // VSTS fixture containing parameterized tests
public class AccountTest
{
    [PexTest]
    public void TransferFunds(int money, int withdraw) {...}
    ...
    [TestMethod, GeneratedBy("Pex", "1.0.0.0")]
    public void TransferFunds_12345() { this.TransferFunds(12, 13); }

}

Why do I need parameterized unit tests anyway?

A parameterized unit tests generally captures more program behaviors than a single unit test which is like a micro-scenario. This will become more apparent when we start looking at some examples. 

If you were already using [RowTest] or [DataSource] as part of your testing, then you will definitely like Pex.

posted on Monday, April 02, 2007 5:52:37 AM UTC  #    Comments [2]
 Tuesday, March 13, 2007

The Pex screencast was a bit mysterious without sound and comments. I've added a 'storyboard' to help you understand it:

   http://research.microsoft.com/pex/screencast.aspx


 

posted on Tuesday, March 13, 2007 7:31:29 AM UTC  #    Comments [1]
 Thursday, March 08, 2007

Pex

I'm thrilled to present the project I joined last October: 'Pex' (for Program EXploration). Pex is a powerfull plugin for unit test frameworks that let the user write parameterized unit tests**. Pex does the hard work of computing the relevant values for those parameters, and serializing them as classic unit tests.

Here's a short screencast where we test and implement a string chunker. In the screencast, we use a parameterized unit test to express that for *any* string input and *any* chunk length, the concatenation of the chunks should be equal to the original sting.

http://research.microsoft.com/pex/screencast.aspx

More info on Pex is available at http://research.microsoft.com/pex/.

** It's actually much more than that... but let's keep that for later :)

posted on Friday, March 09, 2007 1:58:36 AM UTC  #    Comments [5]
 Saturday, February 24, 2007
 Saturday, September 09, 2006

After 2 years in the CLR, I'm moving job (and building) to Microsoft Research. I will be working on Parametrized Unit Testing.

 

posted on Sunday, September 10, 2006 1:21:39 AM UTC  #    Comments [3]
 Tuesday, July 26, 2005

In this post, I’ll show how to build an MsBuild (msdn2) task will automatically generate XSD schemas for your custom tasks. The post is separated in two sections: if you are interested to see how the task works, continue on reading. If you don’t care and want to get straight down to the beef, scroll down until you see TaskSchema reference.

What is MsBuild? Why do we want to generate schemas?

MsBuild is the new .Net build system. It is based on XML files containing the projects, targets and tasks (see also Ant, NAnt). The framework comes with a set of tasks that allows easy compilation of solutions or projects and doing a couple more actions. Of course, everybody has different needs and you will probably end up writing your own specialized task to solve your problems.

When editing a MsBuild script, it is *very* convenient to take advantage of the “built-in intellisense” of XML by attaching it to the MsBuild schema file. You can do this in VS2005 in two mouse clicks (see below How to setup intellisense for msbuild). Unfortunately, this is not true for your custom tasks where you need to create yourself a XSD schema.

I’ll assume you have a basic knowledge of custom msbuild tasks in the following.

Note that NAnt has had this feature (nantschema) for a while now.

What are we looking for?

Before diving into the coding details, let’s see what our “final products” looks like. Let’s build a simple task to use it as our example during the article: the sleep tasks makes msbuild sleep x seconds (note that this implementation is very very poor):

using System;
using System.Threading;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Foo
{
public sealed Sleep : Task
{
private int seconds;

[Required]
public int Seconds
{
get { return this.seconds;}
set { this.seconds = value;}
}
public override bool Execute()
{
this.Log.LogMessage(“Sleeping {0} seconds”, this.Seconds);
Thread.Sleep(this.Seconds * 1000);
}
}
}

The sleep task has a single (required) parameter “seconds”. We expect the schema for this task to look as follows:

<xs:schema
    xmlns:msb=http://schemas.microsoft.com/developer/msbuild/2003
    elementFormDefault="qualified" 
    targetNamespace="http://schemas.microsoft.com/developer/msbuild/2003"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <
xs:include schemaLocation=" Microsoft.Build.Commontypes.xsd" />
    <
xs:element name="Sleep" substitutionGroup="msb:Task">
    <
xs:complexType>
        <
xs:complexContent mixed="false">
            <
xs:extension base="msb:TaskType">
                <
xs:attribute name="Seconds" type="msb:non_empty_string" />
            </
xs:extension>
        </
xs:complexContent>
   
</xs:complexType>
</xs:element>
</xs:schema>

There’s a couple things to say about this schema:

  1. we include the MsBuild schema so we get all the type that are already defined for msbuild,
  2. Sleep is in the substitutionGroup msb:Task,
  3. the extension has “msb:TaskType” as base class to inherit the Task properties,
  4. Since Seconds is an int, we restrict the attribute to msb:non_empty_string. We cannot restrict it to xs:integer to handle cases where the users pases a property, e.g. $(Property).
  5. Latter on, we could add information from the xml documentation into the schema as well.

Now that we know kind of output we are looking for, let’s see what “ingredients” we need.

Recipe ingredients

Here’s a little summary of tools and techniques that we will use to generate the schemas:

  • System.Reflection: we’ll use reflection to enumerate types, find custom attributes, etc…
  • System.Xml.Schema: this namespace contains the object model to create schemas (what a surprise!)
  • System.Xml: to integrate document parts (if available) in the output
  • Microsoft.Build.Utilities: this namespace contains the Task base class,

Building TaskSchema

The TaskSchema has the following properties (it actually has more properties but I’ll skip them for simplicity):

[Required]
ITaskItem[] Assemblies {get;set}
[Output]
ITaskItem[] Schemas {get;}

Assemblies is a list of assemblies containing the tasks to “schematize”. Schemas is an output parameter that will contain the path of each schema, as we will generate one schema per assembly.

This is the high level “factored” Execute method (almost pseudo-code):

CreateAndInitializeSchema(); // (add namespace, includes, etc...)

foreach(string assemblyName in Assemblies)
{
// load error handling comes here
Assembly assembly = LoadAssembly(assemblyName);
// iterating exported types
foreach(Type type in assembly.GetExportedTypes())
{
//if (type is not a task) continue;
if(!typeof(ITask).IsAssignableFrom(type)) continue;
// create a new schema element and name it after the type
// create a simpleType + extension
XmlSchemaElement element = CreateElement(type);
foreach(PropertyInfo property in type.GetProperties())
{
// if (property is defined in some base class) continue;
if (property.DeclaringType != type) continue;
// create schema attribute and name it after property name
// create a simpleType that
XmlSchemaAttribute attribute = CreateAttribute(property);
// add attribute to current element
AddAttribute(element, attribute);
}
}
// saving to disk
SaveSchema(schema);

There are a lot of interesting details to go through to implement this pseudo-code.
I won’t go through all of them. I will rather focus on some parts:

Translating enums into XSD

An enumeration can be represented in XSD by simple type restriction. For example,

[C#]

public enum HelloWorld
{
Hello,
World
}

[XSD]

<xs:simpleType name="HelloWorldType" base="msb:non_empty_integer">
    <
xs:restriction base="xs:string">
        <
xs:enumeration value="Hello" />
        <
xs:enumeration value="World" />
    </
xs:restriction>
</
xs:simpleType>

Getting custom attributes, the generic way

This is a well know (and very handy trick) that add a generic type parameter to a method to “strongly type” it.

T GetAttribute<T>(ICustomAttributeProvider t) where T : Attribute
{
object[] attributes = t.GetCustomAttributes(typeof(T), true);
if (attributes != null && attributes.Length > 0)
return (T)attributes[0];
else
return null;
}

 

Finding and adding documentation to the schema

Adding documention to the schema is straightforward, it is a matter of adding a annotation containing a document element:

<xs:attribute name="Assemblies" use="required">
    <
xs:annotation>
        <
xs:documentation>
            Gets or sets the list of path to analyse.
        </xs:documentation>
    </
xs:annotation>
</
xs:attribute>

The real trouble is to find what kind of documentation we are going to put there. We cannot rely solely on Reflection for this task because MsBuild custom attributes does not store any “documentation” data. Therefore, the best source of documentation is the XML documentation that is generated by the C# compiler (don’t forget to turn it on in Projects -> Properties -> Build). By default, the compiler dumps that file along side of the assembly so it is easy to find. Here’s a sample of how that file looks like:

<?xml version="1.0"?>
<
doc>
    <
assembly>
        <
name>TaskFoo</name>
    </
assembly>
    <
members>
        <
member name="T:TaskFoo.TaskSchema">
            <
summary>
                A Task that generates a XSD schema of the tasks in an assembly.
            </summary>
        </
member>
...

That is sweet. We can access the summary of each member very easily using XPath. For example:

//member[@name=”T:taskType.FullName”]/summary

This expression will return me the summary of the taskType type. Similar constructs can be mode for the property summary.

TaskSchema task reference

A Task that generates the XSD schemas for assemblies containing tasks.

Download: See Task on project distributor. Compiled against .Net 2.0 Beta 2.

Features:
  • Generates ready-to-use XSD schemas. No edition needed.
  • Generates task lists, i.e. the UsingTask sequence, to integrate easily your tasks into MsBuild,
  • If documentation is available, automatically adds documentation to the schema,
  • Task attribute are strongly typed,
  • Generates specific types for enumerations
  • It’s a MsBuild task! It will fit in your automation!
Attributes:
  • Assemblies: Required ITaskItem[] expression. The list of assemblies to analyse.
  • OutputPath: Optional string expression. The desired schemas output path.
  • Schemas: Output ITaskItem[] expression. For each assembly, the corresponding schema path.
  • CreateTaskList: Optional Boolean expression. A value that indicates if TaskList (see below) should be generated as well.
  • TaskLists: Output ITaskItem[] expression. For each assembly, the corresponding task list path. This output is null if CreateTaskList is false.

There are a couple more options. Run TaskSchema to have the full schema!

Examples:

This little msbuild project applies TaskSchema to itself (it is part of Churn.Tasks.dll):

<?xml version="1.0" encoding="utf-8" ?>
<
Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="CreateSchema">

    <
UsingTask AssemblyFile="Churn.Tasks\bin\Debug\Churn.Tasks.dll" TaskName="Churn.Tasks.TaskSchema" />

    <
ItemGroup>
        <
Assemblies Include="bin\Debug\TaskFoo.dll" />
    </
ItemGroup>

    <
Target Name="CreateSchema">
        <
TaskSchema
            Assemblies="@(Assemblies)" 
            OutputPath="Churn.Tasks\bin\Schemas" 
            />
    </
Target>
</
Project>

[Output]

Microsoft (R) Build Engine Version 2.0.50215.44
[Microsoft .NET Framework, Version 2.0.50215.44]
Copyright (C) Microsoft Corporation 2005. All rights reserved.
Build started 5/26/2005 8:19:51 PM.
__________________________________________________
Project "D:\Projects\Churn.NET\Churn.Tasks\taskschema.self.xml" (default targets):
Target CreateSchema:
Analysing bin\Debug\Churn.Tasks.dll
Found documentation file at Debug\Churn.Tasks.xml
Analyzing Churn.Tasks.TaskSchema
Creating Schema bin\Schemas\Churn.Tasks.Tasks.xsd
Create Task list bin\Schemas\Churn.Tasks.Tasks
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.93

[Schema: TaskFoo.xsd]

Execute the sample and see for yourself!

posted on Tuesday, July 26, 2005 12:27:33 PM UTC  #    Comments [5]
 Wednesday, July 21, 2004

The API Design Guidelines encourage developers to check all their arguments and thereby avoid throwing a NullReferenceException.  If an argument is null and the contract of the method forbids null arguments an ArgumentNullException should be thrown. Brad Adams 

So you agree with Brad (I do) and you always check that arguments are not null before using them. This means a little bit more of code but it is worth it. But this means also a lot more of test code because, ideally, you should test that all your methods check all their arguments. This means writing hundreds of boring, repetitive test cases.... and you don't want to do that.

At least I don't so I added a new feature to MbUnit that does it for me.

Test for ArgumentNullException, first iteration:

 Let's see how it works with an example:

public class ArgumentNullDummyClass
{
    public object ClassicMethod(Object nullable, Object notNullable, int valueType)
    {
        if (notNullable == null)
            throw new ArgumentNullException("notNullable");
        return String.Format("{0}{1}{2}",nullable,notNullable,valueType);
    }
}

As one can see, the nullable parameter can be null, while the notNullable parameter is tested. Now, let's create a fixture that tests this method. We will be using the TestSuiteFixture because we will build a TestSuite:

[TestSuiteFixture]
public class MethodTestSuiteDemo
{
    public delegate object MultiArgumentDelegate(Object o,Object b, int i);
    
    [TestSuite]
    public ITestSuite AutomaticClassicMethodSuite()
    {
        ArgumentNullDummyClass dummy = new ArgumentNullDummyClass();

        MethodTester suite = new MethodTester(
            "ClassicMethod",
            new MultiArgumentDelegate(dummy.ClassicMethod),
            "hello",
            "world",
            1
            );
            suite.AddAllThrowArgumentNull();
        return suite.Suite;
    }
}

The MethodTester class takes the following argument: a name, a delegate  and valid parameters of the delegate. By valid I mean parameters that should not make the delegate invokation fail. The AddAllThrowArgumentNull looks for nullable parameters and create a TestCase that will invoke the delegate with the corresponding parameter nulled. In the example, this means that ClassicMethod will be called with:

  • null, "world", 1
  • "hello", null, 1

Test for ArgumentNullException, second iteration:

There are things I don't like in the example above:

  • you need to create a delegate (tedious),
  • you need to create 1 method tester per method (tedious),

Ok, so let's build a ClassTester class that does that for us... The test code now looks as follows:

[TestSuiteFixture]
public class ClassTesterDemo
{
    [TestSuite]
    public ITestSuite AutomaticClassSuite()
    {
        ArgumentNullDummyClass dummy = new ArgumentNullDummyClass();
        ClassTester suite = new ClassTester("DummyClassTest",dummy);
        suite.Add("ClassicMethod","hello","world",1);
        return suite.Suite;
    }
}

That's much better: delegate is gone and we could add more methods to be tested in a single call.

Test for ArgumentNullException, third iteration:

There is still one problem with this technique: there is no way to tell that an argument is authorized to be nulled! In the example, the nullable parameter can be null and the TestCase will always fail because it does not throw ArgumentNullException.

The solution of this problem is done in two steps: first, you, the developper, tag the parameters that can be nulled with a NullableAttribute attribute (could be any of your attributes). In the example, we add a SmartMethod method and the MyNullableAttribute:

[AttributeUsage(AttributeTargets.Parameter,AllowMultiple=false,Inherited=true)]
public class MyNullableAttribute : Attribute
{}

public class ArgumentNullDummyClass
{
    public object ClassicMethod(Object nullable, Object notNullable, int valueType)
    {...}
    public object SmartMethod([MyNullable]Object nullable, Object notNullable, int valueType)
    {...}
}

Next, you must tell MbUnit which attribute is used to tag nullable parameters. This is done with the NullableAttributeAttribute at the assembly level:

[assembly: NullableAttribute(typeof(MbUnit.Demo.MyNullableAttribute))]

Ok, now we just need to update our test case to load the SmartMethod:

[TestSuite]
public ITestSuite AutomaticClassSuite()
{
    ArgumentNullDummyClass dummy = new ArgumentNullDummyClass();
    ClassTester suite = new ClassTester("DummyClassTest",dummy);

    suite.Add("ClassicMethod","hello","world",1);
    suite.Add("SmartMethod","hello","world",1);

    return suite.Suite;
}

The result in MbUnit GUI is as follows: the parameters of ClassicMethod were all tested, nullable included which we want to avoid. The parameters of SmartMethod were all tested excluded nullable because it was tagged. :)

Test for ArgumentNullException, fourth iteration:

 

The more I think about this problem, the more I think FxCop should do that for us...

posted on Thursday, July 22, 2004 12:37:00 AM UTC  #    Comments [0]