# Thursday, July 29, 2004

I have sent the manuscript of my PhD to the jury today. The thesis speaks about stability and control of quasilinear hyperbolic partial differential equations (for example, stabilization of open channels). I won't speak about it in details here but I can give you the title:

Boundary Stabilization Techniques of Quasi-Linear Hyperbolic Initial-Boundary Value Problem.

Of course, the relation to software testing is not obvious... because there is none.

posted on Thursday, July 29, 2004 1:19:00 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [2]
# Wednesday, July 28, 2004

The next version of MbUnit (2.20) will have a new custom attribute that will let you assert on the values of PerformanceCounters: PerfCounterAttribute. (Idea suggested by ISerializable). This means that you can make an assertion an every perfomance counter on your machine!

Here's a sample fixture that shows how the attribute can be used:

using System;
using MbUnit.Core.Framework;
using MbUnit.Framework;
namespace MbUnit.Demo
{
  [TestFixture]
  public class PerfCounterDemo
  {
    [Test]
    [PerfCounter(".NET CLR Memory", "% Time in GC", 10)]
    public void AllocateALotOfObjects()
    {
      ...
    }

    [Test]
    [PerfCounter(".NET CLR Loading", "% Time Loading", 10)]
    [PerfCounter(".NET CLR Security", "% Time in RT checks", 10000)]
    [PerfCounter(".NET CLR Security", "% Time Sig. Authenticating", 10)]
    [PerfCounter(".NET CLR Memory", "# Bytes in all Heaps", 5000000, Relative =true)]
    [PerfCounter(".NET CLR Jit", "% Time in Jit", 10)]
    public void MonitorMultipleCounters()
    {
      ...
    }
  }
}

Note that if you are too lazy to remember the names of the counters, I have written a CodeSmith template that creates a class filled with static helper methods for retreiving the counters. For example, the following class lets you write things like PerfCounterInfo.NetClrExceptions.NbofExcepsThrown.NextValue() using intellisense and without typing errors :)

using System;
using System.Diagnostics;
namespace MbUnit.Core.Framework
{
 public class PerfCounterInfo
 {  
  public sealed class NetClrExceptions
  {
   const string categoryName = @".NET CLR Exceptions";

   public sealed class NbofExcepsThrown
   {
    const string counterName = @"# of Exceps Thrown";

    public static float NextValue()
    {
     return NextValue(Process.GetCurrentProcess().ProcessName);
    }    
   }
   ...
posted on Wednesday, July 28, 2004 3:29:00 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [8]

The next version of TestFu will feature a DataSet graph object (DataGraph class) , i.e. a bidirectional directed graph G(V,E) where

  • V is the set of vertices, one vertex per DataTable in the DataSet, (DataTableVertex class)
  • E is the set of edges, one edge per DataRelation in the DataSet (DataRelationEdge class). The source vertex of the edge is the ParentTable, while the target is the ChildTable.

Why do we need a graph ?

Once you have the graph structure of the database, you use all the algorithms contained in the QuickGraph.Algorithms project: shortest path, topological sort, etc... In fact, you can even use it to draw the graph using the NGraphviz. There are of course other very interresting applications of this structure. For example, you can use the graph to create a table creation order such that will not violate the constraints, or you estimate the complixity of a join, etc...

Let's see some examples..

Creating a graph and basic usage

DataGraph lives in the TestFu.Data.Graph namespace and is built from a DataSet instance:

using Test.Data.Graph;
...
DataSet ds = ...;
DataGraph graph = DataGraph.Create(ds);

Now that we have a graph, we can iterate over it's vertices and edges:

// iterating the vertices (DataTableVertex)
foreach(DataTableVertex v in graph.Vertices)
{
    DataTable table = v.Table;
    ...
}

// iterating the edges
foreach(DataRelationEdge e in graph.Edges)
{
   DataRelation relation = e.Relation;
   ...
}

Let's see what other things we could do with graph.

Drawing the table structure:

This is an obvious usage of the graph and can be done quite easily using the QuickGraph.Algorithms.Graphviz.GraphvizAlgorithm class:

GraphvizAlgorithm gv = new GraphvizAlgorithm(this.graph);
gv.FormatVertex+=new FormatVertexEventHandler(gv_FormatVertex);
gv.FormatEdge+=new FormatEdgeEventHandler(gv_FormatEdge);
System.Diagnostics.Process.Start(gv.Write(dataSource.DataSetName));

...

void gv_FormatVertex(object sender, FormatVertexEventArgs e)
{
    DataTableVertex v = (DataTableVertex)e.Vertex;
    e.VertexFormatter.Shape = NGraphviz.Helpers.GraphvizVertexShape.Box;
    e.VertexFormatter.Label = v.Table.TableName;
}
void gv_FormatEdge(object sender, FormatEdgeEventArgs e)
{
    DataRelationEdge edge = (DataRelationEdge)e.Edge;
    e.EdgeFormatter.Label.Value = edge.Relation.RelationName;
}

The result on a sample DataSet is displayed below:

DataTable ordering

Another interresting application is to create an ordering of the DataTable such that if you fill the tables using this ordering, you will not break any constraint. This solves the old problem "which table should I populate first?". For example, in the example above, the ordering result would be:

  1. Users,
  2. Orders,
  3. Categories,
  4. Products,
  5. OrderProducts

Since this feature has a major interrest in TestFu, it is built-in in the DataGraph class:

DataTable[] tables = graph.GetSortedTables();
In the background, graph uses the QuickGraph.Algorithms.SourceFirstTopologicalSortAlgorithm algorithm class which creates a topological ordering of the vertices of a graph by choosing the vertices with least in degree (very simple algo, home made):

// sort tables
SourceFirstTopologicalSortAlgorithm topo = new SourceFirstTopologicalSortAlgorithm(graph);
topo.Compute();

// output results
DataTable[] result = new DataTable[topo.SortedVertices.Count];
int i = 0;
foreach (DataTableVertex v in topo.SortedVertices)
{
    result[i++] = v.Table;
}
return result;

The SourceFirstTopologicalSortAlgorithm takes a IVertexAndEdgeListGraph instance which graph implements. As you can see, having a graph representation of your DataSet, compatible with QuickGraph opens a realm interresting applications of existing graph theory algorithms.

Next step: "Smart" Random Data generation

Once the table ordering is computed, you can safely generate "smart" random data and feed your DataSet...

posted on Wednesday, July 28, 2004 9:29:00 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [6]
# Tuesday, July 27, 2004

While writing the test for the NUnit fixture loader, I started to have some twisted tests. So twisted, they are worth mentionned in the blog. For instance, the steps I take to test NUnit load are:

  1. Load a NUnit fixture from the Assembly resources (as source code),
  2. Compile it and output an assembly using CodeDom.Compiler namespace,
  3. Load the newly created assembly using MbUnit, look for the tests and execute,
  4. Verify that the tests have been found, are executed and behaved as expected.
  5. Execute all those steps in a fixture

Twisted...

 

using System;
using System.IO;
using System.Configuration;
using System.Reflection;
using MbUnit.Core.Remoting;
using MbUnit.Core.Framework;
using MbUnit.Framework;
using MbUnit.Framework.Utils;
using System.CodeDom.Compiler;
using MbUnit.Core.Reports;
using MbUnit.Core.Reports.Serialization;
namespace MbUnit.Tests.Core.FrameworkBridges
{
  [TestFixture]
  [CurrentFixture]
  public class NUnitBridgeTest
  {
    private SnippetCompiler compiler;
    private ReportCounter counter;
    private ReportResult result;

    [SetUp]
    public void SetUp()
    {
      this.compiler = new SnippetCompiler();
      string nunitFolder = ConfigurationSettings.AppSettings["NUnitFolder"];
      string nunitFrameworkDll = Path.Combine(nunitFolder,@"NUnit.Framework.dll");
      this.compiler.Parameters.ReferencedAssemblies.Add(nunitFrameworkDll);
      this.compiler.LoadFromResource(
         "MbUnit.Tests.Core.FrameworkBridges.NUnitFixture.cs",
         Assembly.GetExecutingAssembly()
        );
      string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
      this.compiler.Parameters.OutputAssembly =
          Path.Combine(path, "NUnitBridgeTest.dll");
    }

    [Test]
    public void TestCaseCount()
    {
      LoadAndRunFixture();
      Assert.AreEqual(4, counter.RunCount);
    }

    [Test]
    public void SuccessCount()
    {
      LoadAndRunFixture();
      Assert.AreEqual(2, counter.SuccessCount);
    }

    ...

    private void LoadAndRunFixture()
    {
      this.compiler.Parameters.GenerateInMemory = false;
      this.compiler.Compile();
      this.compiler.ShowErrors(Console.Out);
      Assert.IsFalse(this.compiler.Results.Errors.HasErrors);

      // load assembly using MbUnit
      using (TestDomain domain = new TestDomain(this.compiler.Parameters.OutputAssembly))
      {
        domain.ShadowCopyFiles = false;
        domain.Load();

        // running tests
        domain.TestTree.RunPipes();
        
        result = domain.TestTree.Report.Result;
        counter = domain.TestTree.GetTestCount();
      }
    }
  }
}

And the loaded fixture is as follows:

using System;
using System.IO;
using NUnit.Framework;
namespace MbUnit.Tests.Core.FrameworkBridges
{
  [TestFixture]
  public class NUnitFixture
  {
    [TestFixtureSetUp]
    public void TestFixtureSetUp()
    {
      Console.Out.Write("TestFixtureSetUp");
    }
    [SetUp]
    public void SetUp()
    {
      Console.Out.Write("SetUp");
    }
    [Test]
    public void Success()
    {
      Console.Out.Write("Success");
    }
    [Test]
    public void Failure()
    {
      Console.Out.Write("Failure");
      Assert.Fail();
    }
    [Test]
    [ExpectedException(typeof(ArgumentNullException))]
    public void ExpectedException()
    {
      Console.Out.Write("ExpectedException");
      throw new ArgumentNullException("boom");
    }
    [Test]
    [Ignore("Because I want")]
    public void Ignore()
    {
      Console.Out.Write("Ignore");
      throw new Exception("Ignored test");
    }
    [TearDown]
    public void TearDown()
    {
      Console.Out.Write("TearDown");
    }
    [TestFixtureTearDown]
    public void FixtureTearDown()
    {
      Console.Out.Write("FixtureTearDown");
    }
  }
}
posted on Tuesday, July 27, 2004 6:17:00 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [2]
# Sunday, July 25, 2004
Download available at www.dotnetwiki.org download page.
posted on Sunday, July 25, 2004 9:24:00 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [4]
# Saturday, July 24, 2004

Reflector.Graph has been recompiled for Reflector 4.0.15.0 along with some bug fixes (unit test generation is working again).

Download it in the www.dotnetwiki.org download section.

posted on Saturday, July 24, 2004 1:33:00 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [8]

This release brings more userfriendlyness to the GUI and generally it returns more information on what MbUnit is doing. See latest release page on this blog for the download links.

New features:

  • New progress bar displaying number of tests, successs, failures, ignore and test duration,
  • Status bar displaying more information,
  • Console application does pop report by default,
  • Added TestDox report type,
  • MbUnit gui can load and save projects (assemblies + treeview state is serialized)

Screenshot of the "new" gui

posted on Saturday, July 24, 2004 10:39:00 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [0]
# Friday, July 23, 2004

MbUnit supports a new report type, similar to TestDox. This reports creates a simple text file, whith fixture and test case names more human readable.

For example, a Test fixture like

[TestFixture]
public class FooTest
{
    [Test]
    public void IsASingletonTest() {}
    [Test]
    public void AReallyLongNameIsAGoodThing() {}
}

MbUnit generates

-- MbUnit.Demo
MbUnit
MbUnit.Demo
    Foo
        - is a singleton
        - a really long name is a good thing

Available in 2.18.1

posted on Friday, July 23, 2004 1:04:00 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [0]

MbUnit now supports a simple way of running a single fixture (the one you are working on) without the need of a GUI or NUnitAddIn. The method is simple: tag your fixture class with the CurrentFixtureAttribute and launch it with the auto-runner:

Consider this little example:

[TestFixture]
public class MyFixture
{
   ...
}
  1. Tag MyFixture with CurrentFixtureAttribute:
  2. Convert the test assembly to a console application and add the following code to your main function:
    using System;
    namespace MbUnit.Tests
    {
        using MbUnit.Core;
        using MbUnit.Core.Filters;
        public class AutoRunTest
        {
            public static void Main(string[] args)
            {
                using(AutoRunner auto = new AutoRunner()) 
                {
                    auto.Domain.Filter = FixtureFilters.Current;
                    auto.Run();
                    auto.ReportToHtml();
                }
            }
        }
    }
    
  3. Launch the console. The fixture will be executed and a HTML report of the tests will pop-out automatically.
(available in 2.18.1)
posted on Friday, July 23, 2004 7:42:00 AM (Pacific Daylight Time, UTC-07:00)  #    Comments [0]
# Thursday, July 22, 2004

This is a question that I received a few times: Peli is my nickname, which was given to me by my parents. Their memory on the reason why is somehow vague:

  • It could comes from the pelican (the bird) because of the movie "Jonathan Livingstone the Seagul", which became a pelican,
  • because Pelican have a big mouth,
  • because my mom did not like "Jonathan"  with the french pronounciation

Cheers,

Peli...

posted on Thursday, July 22, 2004 8:31:00 PM (Pacific Daylight Time, UTC-07:00)  #    Comments [2]