MVPVM: Integration testing using the Presenter

by 20. June 2010 12:17

The MVPVM pattern lends itself to effective integration/unit testing.   Since their is no code in the code-behind and the Presenter processes all business logic against the ViewModel and View it is the best component to perform integration test against. 

In the following application (download from this link DirectoryLookupModularity.zip (5.82 mb)) there are three view models:

  1. CriteriaViewModel - utilized by views E, B and C
  2. DoctorViewModel - utilized by view A
  3. PatientViewModel - utilized by view D

The MVPVM framework used for the attached application consistently uses the following for bootstrapping modules:

The ModuleBase<TPresenter> (see below image) instantiates the specified Presenter, e.g., on line 14 below we identify the "DoctorPresenter" as the presenter.

The PresenterBase<TView, TViewModel> (see below image) specifies the View and it's ViewModel which in this case is DefaultViewA and DoctorViewModel respectively.  On line 23 we register the view (DefaultViewA) with the TopLeft region which was declared in the Shell's XAML.  The remaining logic is the code required to wire-up a CRUD control and to get the current module load counter value so that we can see that the module dependency attributes are working correctly.

These baseclasses do all of the wiring up so that we can focus on business rules; we don't spend a lot of time getting our module up and ready for the requirements at hand.

The integration test for Module A's presenter is shown below (lines 46-52); it verifies that the infrastructure properly wired up the View and ViewModel. 

Did you notice that on line 24 above we set the container to null and on the following line use the container.RegisterServices() method?   On the surface this may look odd but it lends itself to testing the Prism environment.

We use the same RegisterServices in our bootstrapper as we do in our integration/unit test - we do this to ensure our environments match for testing purposes.  To accomplish this we use a IUnityContainer Extension class (IUnityContainerExtension), the only time container will be null is during testing so we instantiate a MockBootstrapper (lines 25-27 below).   From that point on we have the same registrations to ensure our test will run without complaint.

Unit Testing ASP.NET/Client Application Service / Programmatically Starting Web Development Server (WebDev.WebServer.exe)

by 27. March 2010 09:02

What is seemingly a very simple process turned into quite the adventure - a costly one in terms of following dead-ends and beating my head against the wall - I first started with the programmatically started service (failing miserably) and evolved into the attribute driven approach which I finally got to work but it had constraints.....

I will detail how to make both methods work, highlighting areas left out of available blogs and research material that will result in errors that yield no answers on the internet.  

The adventure started with an annoying problem with my EHR unit test - I have a number of test that test the Client Application Service (for security) and if I don't manually start up the ApplicationService web service they will fail - this morning I rolled up my sleeves and decided to automate this process so at any time I can run all test in solution and have the service automatically start for the test that depend on it.

Below shows the syntax for the StartWebApplication() TestContext extension method that does the job of starting up the service during test initialize programmatically. 

Before going into more detail the following source demonstrates how to use the attribute method for starting the ApplicationService:

THE KEY to using attributes is to first ensure you have the namespace available - you'll find many resources that will correctly inform you that you must use the following:

using Microsoft.VisualStudio.TestTools.UnitTesting.Web;

However, what is not easily found is the DLL that this unit test resides in!!!   After a long search and destroy mission (online failed) I started searching the Microsoft.VisualStudio DLLs and found it in the Microsoft.VisualStudio.QualityTools.WebTestFramework 

A second piece of information that can really eat your lunch if it escapes you is that you MUST have a DEFAULT.ASPX file in the service!!!  Since I was using a Client Application Service (which doesn't even have a service, never mind a default.aspx file) I ran into the errors you'll see below that affected both the programmatic method as well as the attribute method.   Ensure you have a Default.aspx file.

CONSTRAINTS

I could be missing something but I could not get a breakpoint to work on the unit test that had this attribute - this was unacceptable but at least I got the web development server to start automajically (for the first time) so I was going to make it work.   I decided to have an initialize (empty) service that would start the service so that it was available for the rest of the unit test.

I then ran into a problem - you cannot control the order of your test (outside of an ordered test).  I want to be able to "run all test in solution" and have it work (which it currently does).   I saw blogs that tell you that you can use the Priority attribute but it doesn't work - later this was confirmed on the MSDN site that holds the information for this attribute; it clearly states that this is not used by the test engine and is only for developer use.

My work-around; I found that the same test always is the first test to run so I put the attribute on it :)  Ugly work-around but it works.   You'll find it on my CanGetCloudContainer() unit test which is always the first test to run in the solution.   Later I was able to get the programmatic approach to work consistently (by adding a default.aspx file) so I really don't need this solution but keep it in there as a code reference (for this blog).   I did code the TestContextExtension so that if a WebDev.Server is available it will not attempt to programmatically load it.   This supports both "all unit test in solution" (attribute) and the programmatic approach (if running only that test fixture during development).

HEAD-BANGERS

ERROR:  The ASP.NET Web application at 'C:\_\_EHR\Layers\Service\GWN.EHR.ApplicationService' is already configured for testing by another test run. Only one test run at a time can run tests in ASP.NET. If there are no other test runs using this Web application, ensure that the Web.config file does not contain an httpModule named HostAdapter.

This error occurs if you are using the attribute method and you crashed out of the unit test.   Behind the scenes when the test starts the Web.Config is modified; the HostAdapter is added to it.  When the test are all completed it is removed.  If you crash out of the test and this is not removed then you will see the above error.   To watch this at work simply load your Web.Config of your service and run the test - you will be notified when the Web.Config file is changed (first to add and the second to remove the HostAdapter statement).

ERROR:  The Web request 'http://localhost:2035/AppService' completed successfully without running the test. This can occur when configuring the Web application for testing fails (an ASP.NET server error occurs when processing the request), or when no ASP.NET page is executed (the URL may point to an HTML page, a Web service, or a directory listing). Running tests in ASP.NET requires the URL to resolve to an ASP.NET page and for the page to execute properly up to the Load event. The response from the request is stored in the file 'WebRequestResponse_CanGetCloudBlobConta.html' with the test results; typically this file can be opened with a Web browser to view its contents.

The above error occurs if the the web application/service does not have a Default.aspx file.   If you debug the test you'll see the ASP.NET Web Development Server load, the test will fail and then the Web Development server will close.

With the Default.aspx file missing you can see the "in progress" test below fails for a "Configuration Error".   At other times I could get the programmatic approach to work without the default.aspx however I will ensure I have one to ensure I don't stumble upon the following error again:

 

The error for CanGetCloudBlobContainer (attribute load of Web Development Server) above had the following "The web site could not be configured correctly" error also: 

Source code for TestContext extension that loads the WebDev.WebServer.exe follows:

using System.Diagnostics;

using System.Linq;

using Microsoft.VisualStudio.TestTools.UnitTesting;

 

namespace GWN.Library.Tests.Extensions

{

    public static class TestContextExtension

    {

        private static Process _currentProcess;

 

        public const string WebDevWebServerExe =
            @"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\WebDev.WebServer.exe";

 

        public static string StartWebApplication(this TestContext testContext,

            string appName, string port, string fullAppPath)

        {

            if (_currentProcess != null)

                return null;

 

            // If other processes, i.e., attribute process, loaded webserver

            // then don't run this process (it is already available).  We only

            // run one service at this point so we'll worry about multiple ones

            // when the need arises..

            if (Process.GetProcesses()

                .Any(process => process.ProcessName.Contains("WebDev.WebServer")))

                    return null;

 

            var fullWebPath = string

                .Format("/port:{0} /path:\"{1}{2}\" /vpath:\"/{3}\"",

                       port,

                       testContext.GetRootPath(),

                       fullAppPath,

                       appName);

 

            var startinfo = new ProcessStartInfo(WebDevWebServerExe, fullWebPath)

                {

                    WindowStyle = ProcessWindowStyle.Hidden,

                };

 

            _currentProcess = Process.Start(startinfo);

 

            return fullWebPath;

        }

 

        public static string GetRootPath(this TestContext testContext)

        {

            var offset = testContext.TestDir.IndexOf("TestResults");

            var path = testContext.TestDir.Substring(0, offset);

            return path;

        }

    }

}

ATTRIBUTE APPROACH (full source since image is cut off)

/// <summary>

/// Determines whether this instance [can get BLOB container].

/// </summary>

[TestMethod]

[HostType("ASP.NET")]

[AspNetDevelopmentServerHost(
   @"C:\_\_EHR\Layers\Service\GWN.EHR.ApplicationService", "/AppService")]

[UrlToTest("http://localhost:2035/AppService")]

public void CanGetCloudBlobContainer()

{

    // Get list

    var blobList = client.ReadContainerList();

 

    // Get first container

    var blobContainer = blobList.FirstOrDefault();

 

    Assert.IsNotNull(blobContainer);

 

    // Use first container (name) to get container from list

    var cloudBlobContainer = client.ReadContainer(blobContainer.Name);

 

    // Assert the names match

    Assert.AreEqual(blobContainer.Name, cloudBlobContainer.Name);

}

VS2010 RC - Unit Testing Azure Create, Read, Update and Delete (CRUD)

by 27. February 2010 04:26

I did some head-banging this morning while writing a unit test for Azure table storage CRUD operations.   My WebRole application uses the PersonDataSource (line 8) as an ObjectDataSource and works without issue so I was perplexed as to why my unit test kept crashing on line 40.   The UpdateItem(testdata) was successfully executing but the value was not being updated to "TestOrganization" as expected.

    1 /// <summary>

    2 /// Determines whether this instance can create read update delete

    3 /// azure table records.

    4 /// </summary>

    5 [TestMethod]

    6 public void CanCreateReadUpdateDeleteAzureTableRecords()

    7 {

    8     PersonDataSource mockData = new PersonDataSource();

    9     EHRPerson testData = null;

   10 

   11     string uniqueId = Guid.NewGuid().ToString();

   12 

   13     //:::::[ CREATE ]:::::::

   14     bool isSuccessful = mockData.CreateItem(new EHRPerson

   15     {

   16         ID = uniqueId,

   17         Name = "EHRTest",

   18         Organization = "EHROrganization",

   19         PersonType = "EHRPersonType",

   20         ProfessionalTraining = "EHRProfessionalTraining"

   21     });

   22     Assert.IsTrue(isSuccessful);

   23 

   24     //:::::[ READ ]:::::::

   25     testData = new List<EHRPerson>(mockData.Read())

   26         .FirstOrDefault<EHRPerson>(p => p.ID.Equals(uniqueId));

   27 

   28     Assert.IsNotNull(testData);

   29     Assert.AreEqual("EHRTest", testData.Name);

   30     Assert.AreEqual("EHROrganization", testData.Organization);

   31     Assert.AreEqual("EHRPersonType", testData.PersonType);

   32     Assert.AreEqual("EHRProfessionalTraining", testData.ProfessionalTraining);

   33 

   34     //:::::[ UPDATE ]:::::::

   35     testData.Organization = "TestOrganization";

   36 

   37     mockData.UpdateItem(testData);

   38     testData = new List<EHRPerson>(mockData.Read())

   39         .FirstOrDefault<EHRPerson>(p => p.ID.Equals(uniqueId));

   40     Assert.AreEqual("TestOrganization", testData.Organization);

   41 

   42     //:::::[ DELETE ]:::::::

   43     mockData.DeleteItem(testData);

   44 

   45     testData = new List<EHRPerson>(mockData.Read())

   46         .FirstOrDefault<EHRPerson>(p => p.ID.Equals(uniqueId));

   47     Assert.IsNull(testData);

   48 

   49 }

What I found was that my item (TItem) parameter was being reset to default items on line 330 (image below) effectively overwriting my changes with original values.    However, if I ran my Cloud application it successfully updated the data (PersonDataSource as ObjectDataSource).   

I discovered that I was being returned the reference of the item that was read previously (line 25 above) which meant I was passing around a reference so line 330 below effectively replaced it with the original contents thus entry = item.  This wasn't a problem with the ObjectDataSource because I trust that ASP.NET creates a new instance and populates it with form values prior to sending it to the ObjectDataSource.

I resolved the issue by updating my TableServiceEntity base class to implement ICloneable so that I don't have to manage it at higher levels.    All of my table entities, i.e., EHRPerson will be POCO so this should work well.  

 

 

Enterprise Library 4.1 - unit test don't work

by 2. March 2009 08:13

Note: Run the "Install Instrumentation" menu option from the Microsoft Patterns and Practices menu or the Unit Test will fail during [TestInitialize] method. 

When first attempting to run Unit Test for Enterprise Library 4.1, I was greeted with the following message (other times it would just hang - VS would go Not Responding): 

Although I have an x64, Intel Core 2 Duo CPU T5750 @ 2.00Ghz system with 4 Gig RAM I also recognized a large number of Unit Test in the solution so I unloaded the following projects

Keeping only the projects I'm currently interested in loaded (reflected by curved arrow above).

Now my Unit Test would actually run but I was greeted with an odd (unexpected) error:

What was odd about this error message was that the current assembly shows "Logging" and the error message complains that it can't load "Logging"; odd that it was complaining that it couldn't load itself.

The key to this error was the PublickeyToken - the current running assembly (project) shows a PublicKeyToken=null where the error has an actual token.  Something was attempting to load a different assembly of the same name but from a .DLL (not project).  

The next step was to locate the offending process - in this case it was the reader that was complaining so as I examined it's value I noted the "RollingFlatFileTraceListenerData".   Running a global search for this class (more specifically - within a .Config file) resulted in the following:

The configuration file was requesting a specific .DLL where our Unit Test has a reference to the actual project - two different .DLLs.

The fix was to remove everything after the Assembly name as shown below - this will allow it to default to the project being used by the Unit Test.

Be sure to rebuild your solution before attempting to run the Unit Test after updating the .Config file.

After complying with the above steps I was able to run the above referenced Unit Test and it passed. 

VALIDATION SOLUTION

Do a solution search and replace for the for the following (without the quotes):
", Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

After the above search and replace you'll find that we're down to 37 failures; many associated with the Performance Counter.

 To be continued...

OTHER CONSIDERATIONS - Proper Setup

Note: I use Visual Studio 2008 Professional Edition

TypeMock - Testing the ASP.NET FileUpload control SaveAs method

by 24. September 2008 10:43

Actually the blog title is somewhat misleading; the objective was to create a method that we can pass a FileUpload control into and it will save it to a temporary file (guid filename) and return the name so that we can process it further.

Unfortunately this objective became quite complicated once we threw TDD into the mix.   We had to throw out what could have been an easy fileUpload.SaveAs(tempFile) command and substitute it with a process that we can Unit Test.  TypeMock helps us do this quite nicely
Cool  Below is the process we will be using from ASP.NET and our Unit Test:

    /// <summary>
    /// Save the FileUpload data as a temp file
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="fileUpload"></param>
    /// <returns></returns>
    public string SaveFileUploadAsTempFile(FileUpload fileUpload)
    {
        // Generate a Temp file in the App_Data\Temp folder
        // and return the file name
        string tempFile = GetTempFile();
 
        // Store the FileUpload control's InputStream (the file)
        // to a fileData stream.  We do it this way for Unit Testing
        // purposes
        Stream fileData = fileUpload.PostedFile.InputStream;
 
        // Use the Stream's StrToFile extension to save the contents
        // to our temp file
        fileData.StrToFile(tempFile);
 
        // Return the name of the temp file that holds our
        // file contents
        return tempFile;
    }

Note: In this BLOG I discuss the FileToStr() and StrToFile() extensions; the StreamExtensions.cs file has comparable code (see end for full source location).

I commented the unit test heavily so I'll just post the Unit Test in its entirety for your review: 

using System;
using System.IO;
using System.Web;
using System.Web.UI.WebControls;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
 
using TypeMock;
using HttpUtility.Tests.Base;
using HttpUtility.Storage;
 
// Holds our string and stream extensions for StrToFile()
using Library.Utility.Extensions;
 
namespace HttpUtility.Tests
{
    /// <summary>
    /// Summary description for FileUploadFixture
    /// </summary>
    [TestClass]
    public class FileUploadFixture : TestBase
    {
        public FileUploadFixture() {}
 
        [TestMethod]
        public void FileUpload_ControlCanWriteToAppData()
        {
            // The TestBase:HttpContextBase constructor will
            // create a HttpContext.Current if it is null  BLOGGED HERE
            HttpContext MockContext = HttpContext.Current;
 
            // Assert that we have a MockContext
            Assert.IsNotNull(MockContext, 
                "HttpContextBase should create HttpContext");
 
            // When the context is retrieved the PhysicalPath
            // property of our TestBase class will be set
            Assert.IsNotNull(PhysicalPath);
 
            // Dynamically generate our MockFolderPath using the 
            // TestBase:HttpContextBase.PhysicalPath property 
            MockFolderPath = PhysicalPath.Replace("default.aspx", "App_Data");
 
            // Instantiate our file Utility class
            FileUploadUtil fileUploadUtil = new FileUploadUtil();
 
            // Setup the TypeMock recorder
            // When MapPath("App_Data") is requested, supply our 
            // MockFolderPath (public static string in TestBase)
            using (RecordExpectations recorder = RecorderManager.StartRecording())
            {
                // GetTempFile() will request this - we'll return
                // our MockFolderPath when it does
                HttpContext.Current.Server.MapPath("App_Data");
                recorder.Return(MockFolderPath);
            }
 
            // Use the fileUploadUtil to get Temp file in App_Data\Temp
            string app_dataPath = fileUploadUtil.GetTempFile();
 
            // Write mockData to temp file using our string extension
            mockData.StrToFile(app_dataPath);
 
            // Ensure our mockData file exists so we can 
            // pull it into a MockStream
            Assert.IsTrue(File.Exists(app_dataPath));
 
            // Read temp file containing mockData into file stream
            FileInfo fileInfo = new FileInfo(app_dataPath);
            FileStream MockStream = fileInfo.OpenRead();
 
            // Instantiate our mock FileUpload control
            FileUpload MockFileUploadControl = new FileUpload();
 
            // Setup the TypeMock recorder 
            using (RecordExpectations recorder = RecorderManager.StartRecording())
            {
                // GetTempFile() will request this - we'll return
                // our MockFolderPath when it does
                HttpContext.Current.Server.MapPath("App_Data");
                recorder.Return(MockFolderPath);
 
                // When the contents from the PostedFile.InputStream is 
                // requested we'll return our MockStream (set above to
                // the contents of app_dataPath)
                recorder.ExpectAndReturn(
                    MockFileUploadControl.PostedFile.InputStream, 
                    MockStream);
            }
            // Call our FileUploadUtil method that will save the 
            // FileUpload control's contents to a temporary file
            string savedFile = fileUploadUtil
                .SaveFileUploadAsTempFile(MockFileUploadControl);
 
            // Retrieve the file just saved
            string savedXML = savedFile.FileToStr();
 
            // Assert that it is equal to the data that was in our
            // MockStream
            Assert.AreEqual(mockData, savedXML);
 
            MockManager.Verify();
        }
 
 
        private TestContext testContextInstance;
 
        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }
    }
}
Source code available HERE Change Set: 40565

TypeMock - Unit test for ASP.NET class utilities

by 22. September 2008 08:29

For our CASK application I am creating a User Import module; I have to import a list of names from an old .NET 1.1 Newsletter application (xml file) into CASK so my client can use it's Newsletter capabilities with existing users.  A user import module (reusable) seemed to be the way to go.

Although a simple utility, I have made a commitment to do TDD from now on so a lot of infrastructure has to be put in place to support it; e.g., the simple process below has to be supported from Unit Test:

The HttpContextBase class takes on the responsibility of ensuring that there is an HttpContext.Current instance; it takes care of this responsibility in it's constructor:


Note: I moved the PhysicalPath line path below line 38 (so it is always set) 

The HttpContext.Current.Server object is a different story - it won't allow me to instantiate a HttpServerUtility object; it is inaccessible.   For this we'll rely on TypeMock; I chose it primarily because it supports SharePoint sealed classes and they have graciously offered us (the open source community) a free licence to use it with our projects.  

Below I configure TypeMock so that when a request for Server.MapPath("App_data") is made that it will return the MockFolderPath; I'll be using this as a location to place the <user>.XML file uploaded via the ASP FileUpload control.

[TestClass]
public class FileUploadUtilFixture :
TestBase
{

[TestMethod]
public void
HttpContext_CanGetContextForUnitTest()
{
    // The TestBase:HttpContextBase constructor will

    // create a HttpContext.Current if it is null
    HttpContext context = HttpContext.Current;
    Assert.IsNotNull(context,
"HttpContextBase should create HttpContext"
);
    Assert.IsNotNull(PhysicalPath);

    // Dynamically generate our MockFolderPath using the

    // TestBase:HttpContextBase.PhysicalPath property (the
    // baseclass used by FileUploadUtil).
    MockFolderPath = PhysicalPath.Replace("default.aspx", "App_Data"
);

    // Instantiate our file Utility class

    FileUploadUtil fileUploadUtil = new
FileUploadUtil();

    // When MapPath("App_Data") is requested supply our

    // MockFolderPath (public static string in TestBase)
    using
(RecordExpectations recorder = RecorderManager.StartRecording())
    {
        HttpContext.Current.Server.MapPath("App_Data"
);
        recorder.Return(MockFolderPath);
    }

    // Use the fileUploadUtil to retrieve our data path

    string
app_dataPath = fileUploadUtil.GetFileFolder();

    // Assert that all is well

    Assert.AreEqual(app_dataPath, MockFolderPath);
    Assert.AreEqual(MockFolderPath, fileUploadUtil.FileFolder);

    MockManager.Verify();
}

Full source code available HERE Change Set: 40436

Unity - Modification to support circular reference

by 21. July 2008 14:52

The following source code changes to the Unity, ObjectBuilder and Tests projects will permit circular references during DI.   All Unit Test passed to include the new unit test below (last code snippet).  The affected areas of code are commented with the following: "// BillKrat.2008.07.22 ID: Circular Reference"


Src\ObjectBuilder\BuilderContext.cs 

        // BillKrat.2008.07.22 ID: Circular Reference
        // New Property
        private IBuilderContext _parentContext;
        /// <summary>
        /// The context that spawned the current context
        /// </summary>
        public IBuilderContext ParentContext
        {
            get { return _parentContext; }
            set { _parentContext = value; }
        }


Src\ObjectBuilder\IBuilderContext.cs

        // BillKrat.2008.07.22 ID: Circular Reference
        // New Property
        /// <summary>
        /// Gets / Sets the parent of the current context
        /// </summary>
        IBuilderContext ParentContext { get; set; }


Src\ObjectBuilder\Strategies\BuildPlan\BuildPlanStrategy.cs

    /// <summary>
    /// A <see cref="BuilderStrategy"/> that will look for a build plan
    /// in the current context. If it exists, it invokes it, otherwise
    /// it creates one and stores it for later, and invokes it.
    /// </summary>
    public class BuildPlanStrategy : BuilderStrategy
    {
        /// <summary>
        /// Called during the chain of responsibility for a build operation.
        /// </summary>
        /// <param name="context">The context for the operation.</param>
        public override void PreBuildUp(IBuilderContext context)
        {
            IBuildPlanPolicy plan = context.Policies.Get<IBuildPlanPolicy>(context.BuildKey);
            if(plan == null)
            {
                IBuildPlanCreatorPolicy planCreator =
                    context.Policies.Get<IBuildPlanCreatorPolicy>(context.BuildKey);

                if(planCreator != null)
                {
                    plan = planCreator.CreatePlan(context, context.BuildKey);
                    context.PersistentPolicies.Set(plan, context.BuildKey);
                }
            }
            // BillKrat.2008.07.22 ID: Circular Reference
            // Added IsCircularReference(context)
            if(plan != null && !IsCircularReference(context))
            {
                plan.BuildUp(context);
            }
        }

        // BillKrat.2008.07.22 ID: Circular Reference
        // New method
        /// <summary>
        /// If the current context matches it's grandparents
        /// then we're in a circular reference
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private bool  IsCircularReference(IBuilderContext context)
        {
            if(context.ParentContext==null)
                return false;;
            if(context.ParentContext.ParentContext==null)
                return false;

            IBuildKey current = (IBuildKey)context.BuildKey;
            IBuildKey parent = (IBuildKey)context.ParentContext.ParentContext.BuildKey;

            return current.Type == parent.Type;

        }
    }


Src\Unity\ObjectBuilder\NamedTypeDependencyResolverPolicy.cs

        public object Resolve(IBuilderContext context)
        {
            Guard.ArgumentNotNull(context, "context");
            NamedTypeBuildKey key = new NamedTypeBuildKey(type, name);
            IBuilderContext recursiveContext = context.CloneForNewBuild(key, null);
            // BillKrat.2008.07.22 ID: Circular Reference
            // Set new ParentContext property
            recursiveContext.ParentContext = context;
            return recursiveContext.Strategies.ExecuteBuildUp(recursiveContext);
        }   



Tests\ObjectBuilder\Utility\MockBuilderContext.cs
Tests\ObjectBuilder.BuildPlan\TestDoubles\TestBuilderContext.cs
Tests\Unity.Tests\TestDoubles\TestingBuilderContext.cs

        // BillKrat.2008.07.22 ID: Circular Reference
        // New Property
        private IBuilderContext _parentContext;
        /// <summary>
        /// Get / Set parent context
        /// </summary>
        public IBuilderContext ParentContext
        {
            get { return _parentContext; }
            set { _parentContext = value; }
        }


NEW UNIT TEST FOLLOWS 

        // BillKrat.2008.07.22 ID: Circular Reference
        // The following is new code

        public interface IFooA  
        { 
            IFooB B { get; set; }
            IFooB BInstance { get; }
            int GetFooCount();
        }
        public interface IFooB
        {
            IFooA A { get; set; }
            IFooA AInstance { get; }
        }

        public class FooA : IFooA
        {
            public List<FooB> blist = new List<FooB>();

            private IFooB _bInstance;
            public IFooB BInstance
            {
                get { return _bInstance; }
            }

            public FooA(IFooB bInjected)
            {
                _bInstance = bInjected;
                blist.Add(new FooB());
                blist.Add(new FooB());
            }

            private IFooB _b;
            [Dependency]
            public IFooB B
            {
                get { return _b; }
                set { _b = value;}
            }

            public int GetFooCount()
            {
                return blist.Count;
            }
        }

        public class FooB : IFooB
        {
            private IFooA _aInstance;
            public IFooA AInstance
            {
                get { return _aInstance; }
            }

            public FooB() { }
            public FooB(IFooA fooA)
            {
                _aInstance = fooA;
            }

            private IFooA _a;
            [Dependency]
            public IFooA A
            {
                get{ return _a;}
                set{ _a = value;}
            }
        }

        [TestMethod]
        public void CanResolveCircularReference()
        {
            IUnityContainer container = new UnityContainer()
                .RegisterType<IFooA, FooA>()
                .RegisterType<IFooB, FooB>();

            IFooA fooA = container.Resolve<IFooA>();
            IFooB fooB = container.Resolve<IFooB>();

            Assert.IsNull(fooA.B.A);
            Assert.IsNull(fooB.A.B);

            Assert.IsNotNull(fooA.BInstance);
            Assert.IsNotNull(fooB.AInstance);

            Assert.AreEqual(2, fooA.GetFooCount());
            Assert.AreEqual(2, fooB.A.GetFooCount());
        }

Related CodePlex link: http://www.codeplex.com/unity/Thread/View.aspx?ThreadId=29302

Unity Unit Test - "Visual Studio does not exist in the namespace Microsoft" error

by 21. July 2008 13:16

After unzipping the Unity Application Block Source Code, loading the Unity solution Visual Studio 2008 and converting the source to VS2008 (from VS2005) I encountered the following error:

error CS0234: The type or namespace name ‘VisualStudio’ does not exist in the namespace ‘Microsoft’ (are you missing an assembly reference?)

The ObjectBuilder project was the offender and upon reviewing the project's references noted that the "Microsoft.VisualStudio.QualityTools.UnitTestFramework" reference was missing (yellow triangle); it was looking for version 8.0.0.0 and VS2008 has 9.0.0.0.

I added the reference from the .NET tab and the solution would now compile however most of the unit test were failing.  I found that the Tests.ObjectBuilder.BuildPlan and Tests.Unity projects were also pointing to version 8.0.0.0 - but were not complaining that it was missing.   After updating all of the project references all of the unit test passed.

Edited: 2008.07.22 - I installed Unity again so that I could have an original source set to work with and found that all I had to do was change the Copy Local property from true to false - then the entire solution compiled without issue.

Notice

Blog videos and references to CodePlex projects are no longer valid