# Monday, June 21, 2004

Reflector.Graph was becoming messy because of external dependencies so I decided to remove some parts of it (TypeGraph, TreeMap) in order to keep funcitonal.

Reflector version: tested for 4.0.6.0 and 4.0.7.0

Installation procedure:

  • Download the Reflector.Graph Binaries  and unzip it in the Reflector directory (it may be unzipped in a Release directory, copy the file aside to Reflector)
  • In Reflector, Tools -> Addin... -> Add -> Reflector.Graph.dll
  • That's it!

In this release, you do not need to create a Reflector.exe.config.

What's in Reflector.Graph:

  • MethodRank (Assembly),
  • TypeRank (Assembly),
  • Unit Test Generator (Type),
  • Mock Geneator (Type),
  • IL Graph (Method),
  • AssemblyGraph (Tools)

What's not in Reflector.Graph:

  • TypeGraph will be release separately because it needs to be compiled agains .Net v1.1
  • TypeTreeMap will be released separately because it has a dependency on the Microsoft TreeMap

Bugs and suggestions:

 

posted on Monday, June 21, 2004 8:56:00 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [2]
# Sunday, June 20, 2004

The Database Populator Framework  follows the same idea of DbMonster (or at least, was partially inspired from it). The purpose of the framework is to provide a flexible (and smart) set of random data generators to populate your database.

Why ?

If you plan to do database testing, the solution are not much: use transaction, create/kill database after each unit test, clean up after each test or use the new technique using Enterprise Services.

The objective of DPF is not to test the database but provide "food" for your unit test. By generating data randomly (satisfying the constraint), you do not need to clean up and you will avoid test clashing on each other. Moreover, you can also use the DPF to test your database under load.

Random but no dumb

In order to generate data for testing database, you need to take into accounts the constraints on the columns and between the tables. By providing a DataSet representing you database, the framework analyses it and create a set of generators. The data generated satisfies all the constraint. Of course, each row generator can be customized for your own needs, but in general, the information contained in the dataset is enough.

The ideas

The idea are rather simple:

  • Each DataColumn has its corresponding IDataGenerator instance,
  • Each DataTable has its corresponding ITablePopulator instance,
  • Each UniqueConstraint has its corresponding IUniqueValidator instance which takes care of ensuring the all unique constraint are validated,
  • Each ForeignKeyConstraint has its corresponding IForeignKeyConstraint instance which will fetch valid foreign key values

The generation of a new row is made inside a ITablePopulator as follows:

  1. Create a row,
  2. Call each IDataGenerator and fill the row,
  3. For each foreign key, get relevant values,
  4. Verify unique constraints, if violated go to 1,
  5. return row

The first bits

The first bits of the framework is located in the MbUnit.Framework.Data namespace. Althout the framework still needs work, the first example is running and is quite promising.

I have built a simple database containing User - Order - Product - OrderProduct:

this.dataSet=new DataSet();

DataTable users=dataSet.Tables.Add("Users");
DataColumn userID = users.Columns.Add("UserID",typeof(int));
DataColumn userName=Users.Columns.Add("UserName",typeof(string));
DataColumn userName.AllowDBNull=false;

DataTable orders=dataSet.Tables.Add("Orders");
DataColumn orderID=orders.Columns.Add("OrderID",typeof(int));
DataColumn orderDate = orders.Columns.Add("OrderDate",typeof(DateTime));
DataColumn oUserID = orders.Columns.Add("UserID",typeof(int));

DataTable products=dataSet.Tables.Add("Products");
DataColumn productID=products.Columns.Add("ProductID",typeof(int));
DataColumn productName = products.Columns.Add("ProductName",typeof(string));
DataColumn productPrice = products.Columns.Add("ProductPrice",typeof(decimal));

DataTable orderProducts=dataSet.Tables.Add("OrderProducts");
DataColumn opOrderID=orderProducts.Columns.Add("OrderID",typeof(int));
DataColumn opProductID=orderProducts.Columns.Add("ProductID",typeof(int));
DataColumn quantity=orderProducts.Columns.Add("Quantity",typeof(int));
// pks
users.Constraints.Add("PK_Users",userID,true);
orders.Constraints.Add("PK_Orders",orderID,true);
products.Constraints.Add("PK_Products",productID,true);
orderProducts.Constraints.Add("PK_OrderProducts",
new DataColumn[]{ opOrderID, opProductID}
,true);
// fks
orders.Constraints.Add("FK_Orders_Users",userID,oUserID);
orderProducts.Constraints.Add("FK_OrderProducts_Orders",orderID,opOrderID);
orderProducts.Constraints.Add("FK_OrderProducts_Products",productID,opProductID);

This database is easily populated using the DPF:

// creating populator
IDatabasePopulator pop=new DatabasePopulator();
// anaylising internal structure
this.pop.Populate(this.db.DataSet);

After that, you can customize the behavior of every data generator. Once this is done, you are ready to "feed" your database:

//getting the users table populator
ITablePopulator userPop = pop.Tables[users];
// adding new row
users.Rows.Add( userPop.Generate() );
posted on Sunday, June 20, 2004 11:03:00 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [8]

Refly is the library that I have developped to make CodeDom usable. (See my CodeProject article here, or the classic Hello World example). Note that Refly comes with XsdTidy, an application that "pretify" the output of the Xml.exe tool.

Download Now

 

posted on Sunday, June 20, 2004 10:17:00 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [3]

If you are doing database testing, you should read this great post by Roy:

Simplified Database Unit testing using Enterprise Services

posted on Sunday, June 20, 2004 8:31:00 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [1]
# Friday, June 18, 2004

The Production Grammar Framework is finally fully integrated into MbUnit as a new Fixture (GrammarFixture).

An example:

I'm currently building a new framework for generating "relevant" data for randomly populating database (similar ideas to DbMonster). As you may have noticed, I don't practive dogfood much so I decided to start now. I'm writing the test code along with the framework (of course, I'm testing myself here so it's a bit twisted). Anyway, I had to test the following collection:

public interface IDataGeneratorCollection : ICollection
{
    IDataGenerator this[DataColumn column]{get;}
    IDataGenerator this[String columnName]{get;}
    void Add(IDataGenerator dataGenerator);
    void Remove(IDataGenerator dataGenerator);
    void Remove(DataColumn column);
    void Remove(String columnName);
    bool Contains(IDataGenerator dataGenerator);
    bool Contains(DataColumn column);
    bool Contains(String columnName);
    void Clear();
}

At first, I decided to write a TypeFixture and produce a bunch of unit tests for that, but I quickly got bored, so I turned myself to production grammars which are much more fun. The grammar for this collection can be summarized as follows (see the stack example):

-- dg is a IDataGenerator
add := Add(dg)
remove := Remove(dg)
contains := Contains(dg)

guardedRemove := guard(InvalidOperatoinException, remove)

empty := add,guardedRemove,contains
nonEmpty := add,remove,contains

startRule := if(collection.IsEmpty) { empty } else { nonEmpty }

MbUnit Attributes

Now that we have built a grammar we need to tell MbUnit to load the grammar it feed it with seeds:  GrammarFixtureAttribute describes a production grammar fixture, GrammarAttribute describes a method that return a IGrammar instance, SeedAttribute returns an object that is feeded into the production constructor.

[GrammarFixture]
public class DataGeneratorCollectionGrammar : Grammar
{
    ... // rules creation etc...

    [Grammar]
    public Grammar This()
    {
        return this;
    }
    [Seed]
    public int Seed10()
    {
        return 10;
    }
    [Seed]
    public int Seed20()
    {
        return 20;
    }
    [Seed]
    public int Seed50()
    {
        return 50;
    }
    [Seed]
    public int Seed200()
    {
        return 200;
    }
}

Screenshot: the grammar test case + the console output

posted on Friday, June 18, 2004 3:51:00 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [3]

Aaron has written a "Hello World" sample using Refly.

Refly is a helper wrapper around the CodeDom namespace that makes it much less "noisy". Refly is used in the Unit Test Generator Addin. If you are using CodeDom regularly, maybe you should have a look at this.

posted on Friday, June 18, 2004 1:14:00 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [2]

This is a quick recap on the available features of MbUnit 2.15.1:

Fixtures:

Fixture type define how MbUnit is going to explore a class and build the test cases.

Fixture can be organized in a number of was. Automatically, they are organized by Namespace and Authors, but you can also tag a http://blog.dotnetwiki.org/archive/2004/05/29/277.aspx, and put them into multiple categories

Decorators:

Decorators are used on the "method" level to modify the behavior of a given test. Decorators can be chained to combine their effect.

Assertion classes

Aside from the classic Assert class, there are a number of specialized assertion classes:

 

posted on Friday, June 18, 2004 6:39:00 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [5]
# Thursday, June 17, 2004

I'm preparing a little Reflector Addin to be able to load and execute MbUnit fixtures inside Reflector. Since the fixture tree contains all the functionalities, it was just a matter of injecting it into Reflector.

Screenshot:

The source code is so short that I'm also publishing (note that I'm using the helper classes described here)

using System;
using System.Windows.Forms;
using Reflector.CodeModel;
using MbUnit.Forms;
namespace Reflector.Graph.Faulty
{ 
    // Reflector package
    public class MbUnitPackage : BasePackage
    {
        [ReflectorWindow("MbUnit")]
        [ReflectorCommandBar(CommandBarTarget.Assembly)]
        private MbUnitWindow MbUnit=new MbUnitWindow(); 
    }

    // Tree View
    public class MbUnitWindow : ReflectorTreeView
    {
        private ReflectorServices services =null;
        public MbUnitWindow()
        {
            this.Dock =DockStyle.Fill;
        }
        // needed to get reflector current element
        public ReflectorServices Services
        {
            get
            {
                return this.services;
            }
            set
            {
                if (this.services!=null)
                {
                    this.services.AssemblyBrowser.ActiveItemChanged-=new EventHandler(this.activeItem_Changed); 
                }
                this.services=value;
                if (this.services!=null)
                {
                    this.services.AssemblyBrowser.ActiveItemChanged+=new EventHandler(this.activeItem_Changed); 
                }
            }
        }
        private void activeItem_Changed(Object sender, EventArgs args)
        {
            this.RemoveAssemblies();
            IAssembly assembly = this.Services.ActiveAssembly;
            if (assembly!=null)
                this.Translate();
        }

        // populate tree with current assembly
        public void Translate()
        {
            IAssembly assembly =this.Services.ActiveAssembly;
            if (assembly==null)
                return;
            this.RemoveAssemblies();
            this.AddAssembly(assembly.Location);
            this.ThreadedPopulateTree();
        }
    }
}
posted on Thursday, June 17, 2004 11:06:00 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [3]
# Wednesday, June 16, 2004

MbUnit 2.1.5.1 Beta is ready for download.  See latest release page on this blog for the download links

Issues, feature requests, and other bugs: please do not post them on the blog. You have two options (please it's easier to track things)

We have a menu!

posted on Wednesday, June 16, 2004 5:53:00 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [17]

This is a preview of a new Addin in the next Reflector.Graph release: Type Tree Map.

A TreeMap is special 2D visualzation of a tree. Since, Reflector provides a tree (Assembly -> Module -> Namespace -> Type -> Members), I wondered if it was possible to visualize with a TreeMap. In .Net, there are 2 controls available that can render treemaps:

I decided to use the later for creating the addin.

Screenshot

Note (1): The nodes represent each part of the type tree from assembly to the class members. Each node is clickable and brings the tree focus to the clicked element.
Note (2): Look at the treemap, and image the nodes are you Namespace/TestFixture/TestCase hierachy. Failed test in red, successfull test in green. Just imagine, that would be the ultimate progress bar for MbUnit!
Note (3): Thanks to Jamie (NUnitAddin) for the idea sharing on this.

posted on Wednesday, June 16, 2004 12:52:00 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [2]