Welcome to MSDN Blogs Sign in | Join | Help

Acceptance Testing Guidance Survey

We have put together a survey to get a bit more input from the community about Acceptance Testing.  If you are at all involved in software development, deployment, or operations acceptance testing proabably impacts you in some way, shape, or form, so you may want to add your insight to what we are working on.

You can find it here: Acceptance Testing Survey

Thanks for the feedback and input.

Enterprise Library 4.0 and Unity 1.1 Shipped

Grigori has announced that Enterprise Library 4.0 has shipped.

You can get EntLib 4 here.  I have been watching this team work hard for the last few months, had a number of conversations with Chris about it, looked at a few problems (note: I did not say I helped solve these problems, I just looked, asked stupid questions, and that allowed Chris to figure them out).  This should be a solid release with some great features, bug fixes, and performance improvements.

Unity 1.1 has also shipped.  EntLib 4.0 is built on top of Unity, and takes advantage of it.  I have said it before, Unity Rocks! 

Now, I need to upgrade to Unity 1.1 for my articles on re-writing the Composite Web Application Block to use Unity.

Posted by mpuleio | 0 Comments

Converting the Composite Web Application Block to Unity - Actually Adding Unity

This is the fifth post in a series. The other post include:

If you want background, go read the earlier posts.

Based upon feedback, I am making the source code available at CWAB and Unity.

First off, I have moved this little side project to source control, so I can avoid the re-work I had to do before I could write this part of the series.

Note to self :

NEVER work without a safety net.  That means both unit tests and source control.

Ok.  Now that that is out of the way....

Let's go add Unity to CWAB, via EDD (formerly TDD).

How can we do this?  First, we need a test fixture.  So, I added CompositionContainerFixture to the CompositeWeb.Tests project as an empty test fixture.  And then I added the following very simple test as a starting point:

[TestMethod]
public void UnityCompositionContainerIsICompositionContainer()
{
    UnityCompositionContainer container = new UnityCompositionContainer();
    Assert.IsInstanceOfType(container, typeof(ICompositionContainer));
}

This will allow me to write enough code to create the UnityCompositionContainer class and ensure that it implements the right interface.

Making the test compile forces me to create a new UnityCompositionContainer class (I added it to the fixture as a nested class for the moment), and the test fails.  No problem.  I add the interface, implement it with methods that throw, and..... We are green again. 

Next step, I copied the unit test RootContainerParentIsNull over, changed its name to NewUnityContainerParentIsNull, updated it to create a new UnityCompositionContainer, and compiled and ran the test.  It passed, which is not idea;l, but I will leave it an move on, knowing it will be important later.  For the next test, I copied ChildContainerHasParent changed its name to NewUnityContainerParentIsNull, updated it to create a new UnityCompositionContainer, and compiled and ran the test... Red. Just like we expected.  To make this work, I could do a bit of throw away work, or I could add Unity.  I feel like I can skip the simplest thing possible, because I know where I want to go. 

However, first, I'm doing a check-in.  I'll comment out the failing test, and sync up.  Just a sec.

<click click>

Ok, now To add Unity.  I grabbed the binaries from MSDN, dropped them in my tree in the Lib folder and we are good to go.  I added references in the CWAB projecct to Unity.DLL and ObjectBuilder2.DLL.  This means we have two completely separate DI systems as part of out code, which is awful.  However, it won't last too long.

Now, we can make that test pass.  I added an IUnityContainer field to UnityCompositionContainer.  I then implemented a constructor to initialize it.  Then we needed to implement CreateChildContainer.  For this, the simplest thing was to create a new constructor for UnityCompositionContainer which takes a parent container as the only parameter.  After a little wire-up we end up with passing tests and this code:

private UnityCompositionContainer(UnityCompositionContainer parentContainer)
{
    Parent = parentContainer;
    wrappedContainer = parentContainer.wrappedContainer.CreateChildContainer();
}
public ICompositionContainer CreateChildContainer()
{
    UnityCompositionContainer child = new UnityCompositionContainer(this);
    return child;
}

Fairly simple.  I will continue moving unit tests over, adapting them, and making them pass.  If there are any interesting deviations from normal, or new tests added, I'll let you know.

<timewarp duration="a short while" />

That was actually fairly simple.  I copied the tests one at a time, replaced the container used with the UnityCompositionContainer, compiled, ran the tests, watched them fail due to NotImplementedExceptions, and fixed them.  Here's the test fixture:

[TestClass]
public class UnityCompositionContainerFixture
{
    [TestMethod]
    public void UnityCompositionContainerIsICompositionContainer()
    {
        UnityCompositionContainer container = new UnityCompositionContainer();
        Assert.IsInstanceOfType(container, typeof (ICompositionContainer));
    }

    [TestMethod]
    public void NewUnityContainerParentIsNull()
    {
        ICompositionContainer container = new UnityCompositionContainer();
        Assert.IsNull(container.Parent);
    }

    [TestMethod]
    public void ChildContainerHasParent()
    {
        ICompositionContainer parent = new UnityCompositionContainer();

        ICompositionContainer child = parent.CreateChildContainer();

        Assert.AreSame(parent, child.Parent);
    }

    [TestMethod]
    public void CanRegisterTypeMappingOnRootContainer()
    {
        UnityCompositionContainer root = new UnityCompositionContainer();

        root.RegisterType<IFoo, Foo>();

        IFoo resolvedIFoo = root.Resolve<IFoo>();

        Assert.AreEqual(typeof (Foo), resolvedIFoo.GetType());
    }

    [TestMethod]
    public void CanRegisterTypeMappingViaTypeObjects()
    {
        UnityCompositionContainer root = new UnityCompositionContainer();
        root.RegisterType(typeof (IFoo), typeof (Foo));

        IFoo resolvedIFoo = root.Resolve<IFoo>();

        Assert.AreEqual(typeof (Foo), resolvedIFoo.GetType());
    }

    [TestMethod]
    public void RequestingTypeMappingForUnmappedTypeReturnsRequestedType()
    {
        UnityCompositionContainer root = new UnityCompositionContainer();

        Foo resolvedFoo = root.Resolve<Foo>();

        Assert.AreEqual(typeof (Foo), resolvedFoo.GetType());
    }

    [TestMethod]
    [ExpectedException(typeof (ArgumentException))]
    public void TypeMappingsMustBeTypeCompatible()
    {
        UnityCompositionContainer root = new UnityCompositionContainer();
        root.RegisterType(typeof (IBar), typeof (Foo));
    }

    [TestMethod]
    public void CanRegisterMultipleTypeMappings()
    {
        UnityCompositionContainer root = new UnityCompositionContainer();

        root.RegisterType<IFoo, Foo>();
        root.RegisterType<IBar, Bar>();
        IBar b = root.Resolve<IBar>();
        IFoo f = root.Resolve<IFoo>();

        Assert.AreEqual(typeof (Bar), b.GetType());
        Assert.AreEqual(typeof (Foo), f.GetType());
    }

    [TestMethod]
    public void RequestingTypeMappingOnChildReadsFromParent()
    {
        UnityCompositionContainer parent = new UnityCompositionContainer();
        ICompositionContainer child = (ICompositionContainer) parent.CreateChildContainer();

        parent.RegisterType<IFoo, Foo>();

        Assert.AreEqual(typeof (Foo), child.Resolve<IFoo>().GetType());
    }

    [TestMethod]
    public void ChildContainersCanOverrideParentTypeMapping()
    {
        UnityCompositionContainer parent = new UnityCompositionContainer();
        ICompositionContainer child = (UnityCompositionContainer) parent.CreateChildContainer();

        parent.RegisterType<IFoo, Foo>();
        child.RegisterType<IFoo, Foo2>();

        Assert.AreEqual(typeof (Foo), parent.Resolve<IFoo>().GetType());
        Assert.AreEqual(typeof (Foo2), child.Resolve<IFoo>().GetType());
    }

    [TestMethod]
    public void CanCreateChildContainer()
    {
        ICompositionContainer container = new UnityCompositionContainer();

        ICompositionContainer child = container.CreateChildContainer();
        Assert.IsNotNull(child);
        Assert.AreNotSame(container, child);
    }

    [TestMethod]
    public void CanRegisterInstance()
    {
        UnityCompositionContainer root = new UnityCompositionContainer();
        root.RegisterInstance(typeof (string), "foo", "bar");
        string returned = (string) root.Resolve(typeof (string), "foo");
        Assert.AreEqual("bar", returned);
    }


    [TestMethod]
    public void CanRegisterInstanceViaGenericWithoutName()
    {
        ICompositionContainer root = new UnityCompositionContainer();
        Foo f1 = new Foo();
        root.RegisterInstance<Foo>(f1);
        Foo returnedFoo = (Foo) root.Resolve(typeof (Foo));
        Assert.AreEqual(f1, returnedFoo);
    }

    [TestMethod]
    public void CanRegisterInstanceViaGenericWithName()
    {
        ICompositionContainer root = new UnityCompositionContainer();
        Foo f1 = new Foo();
        root.RegisterInstance<Foo>("asdf", f1);
        Foo returnedFoo = (Foo) root.Resolve(typeof (Foo), "asdf");
        Assert.AreEqual(f1, returnedFoo);
    }


    [TestMethod]
    public void CanResolveViaGenericWithoutName()
    {
        ICompositionContainer root = new UnityCompositionContainer();
        Foo f1 = new Foo();
        root.RegisterInstance<Foo>(f1);
        Foo returnedFoo = root.Resolve<Foo>();
        Assert.AreEqual(f1, returnedFoo);
    }

    [TestMethod]
    public void CanResolveInstanceViaGenericWithName()
    {
        ICompositionContainer root = new UnityCompositionContainer();
        Foo f1 = new Foo();
        root.RegisterInstance<Foo>("asdf", f1);
        Foo returnedFoo = root.Resolve<Foo>("asdf");
        Assert.AreEqual(f1, returnedFoo);
    }

    [TestMethod]
    public void UnityCompositionContainerImplementsIDisposable()
    {
        UnityCompositionContainer disposableContainer = new UnityCompositionContainer();
        Assert.IsNotNull(disposableContainer as IDisposable);
    }

    // This test is commented out intentionally. The purpose of this test is to show 
    // that if you use the generic version of the RegisterTypeMapping method, if the
    // types aren't compatible it'll fail at compile time. 
    // 
    // This is exactly what happens. However that also means this file won't compile.
    // The test is left in as comments, if you wish to verify this then remove the comments,
    // watch the compile file, and then comment it out again.

    //[TestMethod]
    //public void GenericTypeMappingRegistrationEnforcesCompileTimeCompatibility()
    //{
    //    UnityCompositionContainer root = new UnityCompositionContainer();
    //    root.RegisterType<IBar, Foo>();
    //}
}

Notice, there are no tests for the Services collection.  This is intentional.  We will see if we can avoid implementing the methods at all.

And here is the code to make those tests pass:

public class UnityCompositionContainer : ICompositionContainer, IDisposable
{
    private ICompositionContainer parent = null;
    private IUnityContainer wrappedContainer;

    public UnityCompositionContainer()
    {
        wrappedContainer = new UnityContainer();
    }

    private UnityCompositionContainer(UnityCompositionContainer parentContainer)
    {
        Parent = parentContainer;
        wrappedContainer = parentContainer.wrappedContainer.CreateChildContainer();
    }

    public ICompositionContainer Parent
    {
        get { return parent; }
        set { parent = value; }
    }

    public IServiceCollection Services
    {
        get { throw new NotImplementedException(); // return services; 
        }
    }

    public void RegisterInstance(Type t, object instance)
    {
        wrappedContainer.RegisterInstance(t, instance);
    }

    public void RegisterInstance(Type t, string name, object instance)
    {
        wrappedContainer.RegisterInstance(t, name, instance);
    }

    public void RegisterInstance<TInterface>(TInterface instance)
    {
        wrappedContainer.RegisterInstance<TInterface>(instance);
    }

    public void RegisterInstance<TInterface>(string name, TInterface instance)
    {
        wrappedContainer.RegisterInstance<TInterface>(name, instance);
    }

    public void RegisterType<TRequested, TReturned>() where TReturned : TRequested
    {
        wrappedContainer.RegisterType<TRequested, TReturned>();
    }

    public void RegisterType(Type requested, Type returned)
    {
        wrappedContainer.RegisterType(requested, returned);
    }

    public object Resolve(Type typeOfItem)
    {
        return wrappedContainer.Resolve(typeOfItem);
    }

    public object Resolve(Type typeOfItem, string name)
    {
        return wrappedContainer.Resolve(typeOfItem, name);
    }

    public T Resolve<T>()
    {
        return wrappedContainer.Resolve<T>();
    }

    public T Resolve<T>(string name)
    {
        return wrappedContainer.Resolve<T>(name);
    }

    public object BuildItem(IBuilder<WCSFBuilderStage> builder, object item)
    {
        throw new NotImplementedException();
    }

    public ICompositionContainer CreateChildContainer()
    {
        UnityCompositionContainer child = new UnityCompositionContainer(this);
        return child;
    }

    public void Dispose()
    {
        wrappedContainer.Dispose();
        wrappedContainer = null;
    }
}

We are now in a green state, time to check in.

Abusing Source Control

Agile teams usually check in very often.  Some teams check in every time they hit green.  I think that is a bit of overkill, unless you have a source control system with NO overhead.  I check in when I complete a feature or a story, and usually at a few good, green stopping points in the process, like I have been doing.  This was a good stopping point, and my next task is a bit risky, so this is a perfect time to check in.

This is a long enough post, even though I didn't do all that much, that I will call it quits for today.  Next post, actually use the UnityCompositionContainer, and then nuke the old CompositionContainer.

ScrumBut

I worked on my first XP project with John Boal.  He recently did a post on ScrumBut.  I have mentioned ScrumBut and Scrummerfall before, but this is a good, quick read with a few good tips.  A lot of the concepts carry over to XP as well.

 

I'll add something though: Make sure your stories have acceptance criteria defined before you start working on them. This way you know when you are done. :)

 

Enjoy.

Posted by mpuleio | 0 Comments

We really do listen to community feedback

The other day, we shipped the Smart Client Software Factory April 2008 Release. Before we shipped, I asked the team to audit all the open work items in the queue on the SCSF community site's Issue Tracker and determine what we had fixed.  We had used the items in the Issue Tracker before and during the project, to help guide some of the bug fixes and features.  However, the audit allowed us to do some clean up and ensure we fixed a few things.  Today, I used the results of that audit, and closed a few work items. 

<Sidebar>

I did cheat a bit: I used the Visual Studio Team System integration with CodePlex so I could open up the list of all open work items in an Excel spreadsheet and publish changes back to the live Codeplex site.  This made bulk editing a whole lot simpler, and saved me a lot of time. 

</Sidebar>

Here are the results of the audit and work item closures:

  • Out of 89 open work items/ issues, we closed 45 today.  A number of these had been fixed in the May 2007 release and never closed, a number were fixed in this release, and some were related to different weekly drops.
  • Out of the top 25 items (by community votes), we closed 13.
  • Looked at another way, we closed 1/2 of the open issues, and 1/2 of the top issues. Not bad.

So, keep up the discussion in our communities.  We reply on the discussion boards, we actually do look at the open work items on occasion, and we do listen to the community.

Smart Client Software Factory – April 2008 Release is available on MSDN

The April 2008 release of the Smart Client Software Factory is now available at http://msdn2.microsoft.com/en-us/library/aa480482.aspx

This is a port of the last release (May 2007, if I recall correctly) to VS2008.  No new features were added.  A few bugs were fixed, and a number of work items from CodePlex were closed.

This release supports Enterprise Library 3.1.  It does not support Enterprise Library 4.0.  If you want EntLib 4.0 (once it is released) you have the source code, and should be able to get it to work, if you really need to.  I would not recommend it, as you will end up with two containers (Unity and the CAB container), which means code bloat and challenges deciding where objects should go.

 

Converting the Composite Web Application Block to Unity - Ummmm...Oooops.

This is the forth post in a series. The other post include

If you want background, go read the earlier posts.

Based upon feedback, I am making the source code available at CWAB and Unity.

In the last installment I wanted to remove the following from the ICompositionContainer:

  • static methods
  • Builder
  • Locator
  • Containers
  • Services

We completed the first four. In this installment, we will remove the Services collection, replacing it with using RegisterInstance and Resolve. After that, we will compare our ICompositionContainer to IUnityContainer, see what else we need to do, and may even pull in Unity.

Adding a few new methods

Before we do this, I want to add a generic overload to Resolve and one to RegisterInstance.  I like the way the generic calls on Unity look, compared to all the typeof() and casting we have done so far. 

I added the following tests, one at a time, and made them pass:

[TestMethod]
public void CanRegisterInstanceViaGenericWithoutName()
{
    ICompositionContainer root = new TestableRootCompositionContainer();
    Foo f1 = new Foo();
    root.RegisterInstance<Foo>(f1);
    Foo returnedFoo = (Foo)root.Resolve(typeof(Foo));
    Assert.AreEqual(f1, returnedFoo);
}

[TestMethod]
public void CanRegisterInstanceViaGenericWithName()
{
    ICompositionContainer root = new TestableRootCompositionContainer();
    Foo f1 = new Foo();
    root.RegisterInstance<Foo>("asdf", f1);
    Foo returnedFoo = (Foo)root.Resolve(typeof(Foo), "asdf");
    Assert.AreEqual(f1, returnedFoo);
}


[TestMethod]
public void CanResolveViaGenericWithoutName()
{
    ICompositionContainer root = new TestableRootCompositionContainer();
    Foo f1 = new Foo();
    root.RegisterInstance<Foo>(f1);
    Foo returnedFoo = root.Resolve<Foo>();
    Assert.AreEqual(f1, returnedFoo);
}

[TestMethod]
public void CanResolveInstanceViaGenericWithName()
{
    ICompositionContainer root = new TestableRootCompositionContainer();
    Foo f1 = new Foo();
    root.RegisterInstance<Foo>("asdf", f1);
    Foo returnedFoo = root.Resolve<Foo>("asdf");
    Assert.AreEqual(f1, returnedFoo);
}

 

In making them pass, I added the following to the ICompositionContainer interface:

T Resolve<T>();
T Resolve<T>(string name);
void RegisterInstance<TInterface>(TInterface instance);
void RegisterInstance<TInterface>(string name, TInterface instance);

This will help a bit with the look, feel, and style of the code, now for the real work.

Removing the Services Collection

Why do we want to remove the Services collection?  Since Unity handles this sort of functionality, we can offload it entirely to Unity.  This will cut a bit of code out of our implementation.

Let's do this the simple way, (I like to call it hack and slash development) and just remove the Services collection from the ICompositionContainer interface.  This will result in a number of build errors (twenty or so, in fact).  However, we can fix each of them easily.  Any call to add a service becomes a RegisterInstance call, and any call to get a service becomes a Resolve call.  So, we will hack each problem until we are in a green state again.  The other option, for the less daring, is to search for all uses of Services, change them one at a time, and make sure we are green at each step.  Today, I am feeling brave (read: reckless, or overly caffeinated), so I took the other approach.  If I were pairing with someone, they would probably stop me. :-)

Once CWAB compiles, we still need to get the unit test library to compile.  <click click click> <swear> <click click click>.  The biggest challenge here is that Services.AddNew<T, IT> and RegisterType<IT, T> have the generic parameters in reversed order.  Aaargh.

Everything compiles, but I have a problem: 34 unit tests are failing.  This is not optimal.  Now, why are they failing?  After looking at the first few, it looks like I removed Services from the interface, and forgot to remove it from the CompositionContainer.  The result is that some tests are still using the ServicesCollection.  Oooops.

After removing Services from CompostionContainer, and getting everything to compile again, the test results are.....

Ouch!  40 failing unit tests.  That is not good.

However, after some investigation, I can remove a couple of classes from our solution, as they are no longer necessary, and are just causing problems.

ServiceDependencyParameterResolver
ProviderDependencyParameterResolver
ProviderDependencyAttribute
ServiceDependencyAttribute

After removing them, there is a bit of code cleanup required, to remove references.  All of the ServiceDependencyAttributes I replaced with ObjectBuilder DependencyAttributes.  The ProviderAttributes, I commented out for the moment.

Wow. Progress. we are down to 37 failing tests. After looking at a few of them, where instances were not the same, I changed the SingletonPolicy in Resolve, and we are down to 24 failing tests.

Oh, gotta take a break.

<TimeWarp>Several Days Fly By</TimeWarp>

I got interrupted from getting this working the other day.  Now, I am starting with broken tests.  I hate that.  I guess I was a bit too reckless.  Well, I have a few options:

  1. I can continue and see this through
  2. I can timebox to a hour, and then roll back, and try again by taking smaller steps
  3. I can give up now and try again from the last known good state.

I am going to opt for number 1.5: timebox to two hours, and depending on where I am, make a decision.

<timewarp duration="1 hour" />

@#$%^%$#@#$!!!

<timewarp duration="a few days" reason="I needed to think about it" />

I have determined that I got a bit overzealous.  For the moment, the Services collection is necessary, and we can remove it once we have Unity in place to provide the necessary functionality.  It will stay as part of the interface, and will continue to provide functionality until we no longer need it.  However, it will eventually go away.  How did I arrive at this conclusion?  Well, I could not get the failing unit tests to pass in a reasonable amount of time.  Moving the functionality requires a lot more code than is really practical for throw-away code.  Oooops.  Everyone makes mistakes. 

As a result, I need to roll back a lot of changes.  Unfortunately, I did not back up everything (or do a check in) before starting down the path of removing the services collection.  Net result: I need to roll back everything, and then re-do the first half of this article. Double @#%$@%!

I'll revert and then rework the code up to the section Removing the Services Collection.  I'll get the code posted (with the other source code) before I start the next installment.

However, I wanted to post this article sooner rather than later, so folks don't think I have dropped the series.  Enjoy.

Smart Client Software Factory April 2008 Release Candidate Available

Friday, I posted we had a solid Beta.  Today, I am letting you know that SCSF now has a Release Candidate (RC).  The bug that appeared Friday is, we think, fixed.  We actually published the RC before we completed any internal testing, so the customer who reported the issue would have a chance to verify the fix works on their system ASAP.  Don't worry, we will do a solid test pass before determining if this RC will become the official release. (The fact that we are confident in our build system and the automated tests there helps with this sort of turnaround. :-) )

Please try out the Smart Client Software Factory April 2008 Release Candidate, and report any issues on the SCSF CodePlex community site.

Smart Client Software Factory April 2008 Beta Available

The SCSF April 2008 Beta Release that supports Visual Studio 2008 is now available.

We fixed all the known issues from the Alpha.  It is solid, and may actually be a release candidate, rather than a beta.

Enjoy.

Acceptance Test Engineering Guidance

As I mentioned before (Acceptance Testing Guidance, Grigori's Take on the Acceptance Testing Project), I am working on guidance around acceptance testing with Grigori.

We now have alive CodePlex site that we can work from: patterns & practices: Acceptance Test Engineering Guidance

We will be posting more as we really get ramped up.  We have a LOT of ideas that we will post and talk about.  We will also post bi-weekly (or close) drops, probably in the form of Word documents, showing what we have so far, and asking for input.

Smart Client Software Factory April 2008 Alpha Available

For the past month or so, Blaine and I have been overseeing the development of the April release of the Smart Client Software Factory.  This release is being done mostly by a team of vendors, freeing Blaine to run Prism and I to run the Acceptance Testing Guidance project.  Blaine and I are still very involved, and I still review code changes at random, but the team does most of the work.  The team has been doing a great job, and I think the community will be pleased with the results.

This is a port of SCSF to VS2008 and the .NET 3.5 framework.  It uses Enterprise Library 3.1, not 4.0, intentionally.  There is very little in 4.0 that will effect CAB and SCSF development, except Unity.  Using Unity would require a nearly full re-write of CAB, and we don't currently have the time or people to do it right and deliver on our other commitments.  However, if you really need EntLib4.0, it should work, and if not, you have the source code to fix it.

We did need to create a custom data provider to wrap the SqlCE functionality, as the version number of the platform DLL went from 9.x to 3.5.  This replaces the EntLib 3.1 provider for SQLCE. 

Also, this version of SCSF, just like the last one, supports hosting WPF controls in your WinForms CAB application.  It does not support a full WPF app.  For that, you want to see Prism or the Smart Client Factory Contrib project on CodePlex.

We are also fixing a few bugs, and updating the guidance package (Visual Studio automation) to work in VS2008.

You can download the Alpha release from the SCSF CodePlex community site

Warning: This is an Alpha.  We did a minimal amount of testing ("It compiles and links."  -- "Good enough.  Ship it"), and the computer we installed it on still boots, still runs VS, and seems ok.  Use at your own risk.

We are trying to get this project wrapped up this month.  If you see issues, please post them to the Issue Tracker at the SCSF CodePlex community site, and/or post to the discussion forum there.  We will try to get any major problems, but will not be adding features.

Blaine is also posting about this SCSF April 2008 Alpha for Visual Studio 2008 Published to CodePlex

Converting the Composite Web Application Block to Unity - Clean Up ICompositionContainer

This is the third post in a series. The other post include

If you want background, go read the earlier posts.

Based upon feedback, I am making the source code available at CWAB and Unity.

In the last post, we started getting closer to my eventual goal. However, we still need to get rid of the static methods, Builder, Locator, Containers, and Services. 

Why?

  • Static methods will make the necessary refactorings a pain in the.... well, a pain.
  • Builder and Locator are handled by Unity internally, and we no longer need to deal with them directly. 
  • Containers will just be registered in the root container by module name, and we can use the WebClientApplication.FindModuleContainer method when we need to. 
  • Then there are CWAB Services.  These services will probably just go away.  Global Services are types that are Registered on the Root Container as singletons, and module services are types registered on the appropriate Container as singletons.  This will be really simple once we get Unity tied into the solution. 

Once we get rid of these items on the interface, we will want to add a few from the IUnityContainer, namely CreateChildContainer, and at least a few overloads (if not all of them) for RegisterType, RegisterInstance, and Resolve.

Then, we will add a new type of container to the project, a CWABUnityContainer, and maybe a CompositionContainer factory.  The CWABUnityContainer will be a facade that implements ICompositionContainer and hides a real UnityContainer under the hood.  After that, things should be simple, allowing us to delete the old container and its code, and then do a bit of re-organizing.

Note: Since this is a proof of concept, not what I would call "shipping code", I have turned off creating XML comments in the solution.  With the volume of changes, I was getting annoyed with all the warnings.

Removing Static Methods from CompositionContainer

There is only one static method on CompositionContainer, and it relies on the Locator property of the container object parameter to work.  In removing this, we can simplify the type, and remove the only dependency on the Locator property.  Let's change BuildItem to be a public, non-static method, and add it to the ICompositionContainer interface for a little while.

Everything compiles.  Tests green (except for the ones I had commented out near the end of the last article.

Removing ObjectBuilder specific parts of the interface

Let's do these one at a time, starting with Builder.  Comment it out in the interface, and....

Two parts of the test fixture fail to compile:

  • CreateRootContainerInitializesContainer needs a line commented out, since we changed the semantics of the method
  • MockWebClientApplication needs a change to the ApplicationBuilder property to return null for the moment, with a comment to come back later.

Now we can compile, and run the tests, and we are green. However, I did notice something that I want to take care of before I go any further.... IWebClientApplication has an ApplicationBuilder and a PageBuilder, which can go away.  The Container will handle the responsibilities of these two properties.  If we delete these properties from the interface, the MockWebClientApplication and WebClientApplication, we get some compile errors in WebClientApplication, which lead us down an ugly path. Instead, we will leave these properties ONLY in WebClientApplication, and make a note to delete them later.

Compile -> Good. 

Tests -> Green.

Next Step, the Locator...

If we remove it from the interface, we have compilation problems in WebClientApplication.BuildItemWithCurrentContext where we call BuildItem.  Let's roll back, change the signature of BuildItem to not have a locator, and the implementation to use the current container's locator, and then re-do the change.  Again, we will leave the property only on the CompositionContainer, even though it is not part of the interface, and add a few comments.  After a quick change to the test CreateRootContainerInitializesContainer, everything is green, and all tests pass. 

The Containers collection

If we remove the Containers property from the ICompositionContainer interface, we have problems in the ModuleLoaderService.  The ModuleLoaderService understands how the CompositionContainer works, and can add new containers (one for each module) to the collection.  We also have challenges in the DefaultModuleContainerLocatorService, where we need to find a container in the collection.  If we think about how Unity works, both of these problems can go away if we find another another way to get child containers, and to create child containers.  Unity has the Resolve method, which can take a name parameter to get a named instance of an object (this handles getting a child container). We also have the CreateChildContainer method, to help with the creation, as well as RegisterInstance to give a created instance a name to use later.

Let's roll back removing the Containers property, add the RegisterInstance and Resolve methods (that use a name) to the interface, test them, then add the CreateChildContainer method to the interface, and test it.  Once we have those pieces, we can re-work ModuleLoaderService and DefaultModuleContainerLocatorService to use the new methods.  Once we do all that, we can remove Containers from the ICompositionContainer interface without problems.

So, let's start with RegisterInstance.  Since I know whatever implementation I come up with is a throw away implementation, and it only needs to work well enough NOT to break the existing code, I am going to keep this simple. 

First, a unit test added to CompositionContainerFixture:

[TestMethod]
public void CanRegisterInstance()
{
    TestableRootCompositionContainer root = new TestableRootCompositionContainer();
    root.RegisterInstance(typeof(string), "foo", "bar");
    string returned = (string) root.Resolve(typeof (string), "foo");
    Assert.AreEqual("bar", returned);
}

This tests for the behavior that Unity will have.  I will add the following to the ICompositionContainer to get it to compile:

void RegisterInstance(Type t, string name, object instance);

And then add the stupid implementation:

public void RegisterInstance(Type t, string name, object instance)
{
}

Everything compiles, and the test fails, horribly.

Now, to get the test to pass, RegisterInstance becomes:

private Dictionary<string, object> _registeredInstances = new Dictionary<string, object>();
public void RegisterInstance(Type t, string name, object instance)
{
    _registeredInstances.Add(String.Concat(t.FullName, name), instance);
}

Now, I know that is an ugly, bad, horrible monstrosity of an implementation.  It is also the simplest thing that will work. :-)  I also know I could use OB to do this, but again, I am keeping things simple, knowing I will throw away the implementation in a few hours.

Resolve changes a bit too.  I added an overloaded version, and then made the unit test above pass by making the code look like this:

public object Resolve(Type typeOfItem)
{
    string temporaryID = Guid.NewGuid().ToString();
    return Resolve(typeOfItem, temporaryID);
}

public object Resolve(Type typeOfItem, string name)
{
    string key = String.Concat(typeOfItem.FullName, name);
    if (_registeredInstances.ContainsKey(key))
    {
        return _registeredInstances[key];
    }
    
    PolicyList policies = new PolicyList();
    policies.Set<ISingletonPolicy>(new SingletonPolicy(false), typeOfItem, name);
    policies.Set<ICreationPolicy>(new DefaultCreationPolicy(), typeOfItem, name);
    policies.Set<IPropertySetterPolicy>(new PropertySetterPolicy(), typeOfItem, name);

    return _builder.BuildUp(
        _locator,
        typeOfItem,
        name,
        null,
        policies);
}

Compile.  Run Tests.  We are Green.

Now to add CreateChildContainer.  First, we need a unit test:

[TestMethod]
public void CanCreateChildContainer()
{
    ICompositionContainer container = new TestableRootCompositionContainer();
    
    ICompositionContainer child = container.CreateChildContainer();
    Assert.IsNotNull(child);
    Assert.AreNotSame(container, child);
}

To make that compile and then pass, I added CreateChildContainer to the interface, the class, and then implemented it.  Simple.  And we are Green again.

Next step: remove from ICompositionContainer the Containers property, compile, and it fails.  This requires minor tweaking to the ModuleLoaderService and DefaultModuleContainerLocatorService. Now, we compile.  However, the Containers property is still on the CompositionContainer.  After we remove it from there, we have to fix a lot of unit tests so that they compile (and removing a few that no longer make sense, semantically).  This is simple, but tedious.  <click> <click> <swearing> <click> <click> ...

Ok, we are now compiling and all unit tests pass.

I need a break, so we will cut this a little shorter than I had hoped.

In this installment I wanted to remove the following from the ICompositionContainer:

  • static methods
  • Builder
  • Locator
  • Containers
  • Services

We completed the first four. In the next installment, we will remove the Services collection, replacing it with using RegisterInstance and Resolve. After that, we will compare our ICompositionContainer to IUnityContainer, see what else we need to do, and may even pull in Unity.

Web Client Software Factory Guidance Assets are now Available on MSDN

Some of you may remember that waaaay back in October (and earlier) the Web Client Software Factory team was shipping these things called "bundles".  A bundle was all a developer needed to get started and learn about a single concept, like the Model View Presenter pattern in a web application, or contextual auto-complete.  These bundles were released for VS2005 and .NET 2.0 on the WCSF community CodePlex site.

Now, the same bundles for VS2005 with .NET2.0 and new bundles for VS2008 with .NET 3.5 are available on MSDN's Web Client Software Factory page.  However, due to factors I do not understand and that are beyond my control, we are now calling these "Guidance Assets".

The first question everyone is going to ask is :

"How are these different from the Web Client Software Factory - February 2008?"

The Guidance Assets for .NET 3.5 are identical to the same assets inside the WCSF February release. This packaging just allows developers to grab one or two pieces of the factory at a time, or to share with a co-worker to get them up to speed on a concept.  For example, the Web Client Contextual AutoComplete Application Block for .NET Framework 3.5 is EXACTLY the same as the Autocomplete Quickstart in the factory, with everything you need to get started and stand alone documentation.  The .NET2.0 versions of the assets are identical to what we shipped in October on CodePlex (in fact, they were copied from CodePlex to the MSDN download center).

Why did we post the bundles on MSDN?

A number of customers complained that they wanted to use the bundles but their corporate policy does not allow them to use anything from CodePlex or other open source sites.  However, MSDN is a trusted source in their companies. To help these customers, we have have two distribution channels for identical assets.  :-)

Blaine has already blogged about this, Web Client Bundles for .NET 2.0 and .NET 3.5 Available on Download Center

Here is a comprehensive list of click-able links for all the ZIP files:

.NET 3.5 Assets for Visual Studio 2008: (All these are included in the Feb release of the factory, Web Client Software Factory - February 2008)

.NET 2.0 Assets for Visual Studio 2005: (These are what we released in October-ish)

Unity Shipped

I am a little late to the party, but Unity shipped last week.

Here are a few other posts about it:

I have used Unity in an internal project here at p&p, as well as a proof of concept re-write of CWAB using Unity.  The interface is clean and simple.  It does what you want.  Configuration is easy.  It makes unit testing simpler via de-coupling. Unity rocks. 

Grigori's Take on the Acceptance Testing Project

The other day, I mentioned a new project here at p&p, Acceptance Testing Guidance,

Grigori has his own take on the project, Acceptance Test Engineering Guidance - project kick-off.

Check it out.

Posted by mpuleio | 1 Comments
More Posts Next page »
 
Page view tracker