Posts tagged ‘Unit Testing’

At long last (On a couple of levels I have to add)!

First and foremost – after a long absence from blogging due to a life-changing event (i.e. recent addition to the family) I have managed to write up an article that has been on my mind since June last year! Secondly, because I finally managed to get the example to work – after months of on and off attempts I had been blocked by a very silly and obvious issue (more later) and this evening I managed to concentrate and see it through.

So what’s the big deal?

My desire was to write a blog explaining the beauty of using POCO from EF 4.0 all the way up through WCF to a client application. I had naively assumed that it would be a straightforward case of building the EFDM, creating my POCO classes, create the appropriate Context Interface (see my earlier blog article on creating an appropriate Context Interface) and then write the WCF service to use the EFDM and expose the same POCO classes to the client – how naïve!

The issue actually came up when I tried to pass the EF “filled” POCO classes back through the WCF service. Bang! I got stumped with the following exception:

System.ServiceModel.CommunicationException: The underlying connection was closed: The connection was closed unexpectedly. ---> System.Net.WebException: The underlying connection was closed: The connection was closed unexpectedly.
   at System.Net.HttpWebRequest.GetResponse()
   at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   --- End of inner exception stack trace ---

Although I had the WCF Tracing enabled; I couldn’t for the life of me figure out what it was. Finally after digging through fresh traces I read carefully what the buried exception was:

There was an error while trying to serialize parameter http://tempuri.org/:GetDiverResult. The InnerException message was 'Object graph for type 'DiveLogger.Base.DataContracts.DiveProfile' contains cycles and cannot be serialized if reference tracking is disabled.'.  Please see InnerException for more details.

Of course! How silly of me! It was the fact that the navigation properties of my entities were actually causing cyclic references. Now there was a couple of ways I could do this.

  1. Scrutinize my navigation properties and make sure that the return reference properties were made private (this way the XML Serialization of WCF would overlook it as they would be POCO (i.e. no DataContract attributes here!) – it does work as I tried it out for a laugh.
  2. Utilize the blogged “Cyclic References Aware Contract Behavior” derived from IContractBehavior example. This would allow me to pass my POCO class through un-changed and not cause an exception (that would shutdown my service connection unexpectedly).

In the attached code example I have used the second option as I want to try and demonstrate how we can go from Data Model through EF context to the client via a WCF Service, without decorating our class with any special attributes or referencing any EF or Serialization classes – i.e. real to goodness POCO!

As my regular readers will recognize by now that my reason for being so excited about this (apart from the ability to inject interfaces and have my separation of concerns) is for the all important Unit Tests – after all what fun would it be?

The idea of this exercise was to show that with .NET 4.0 we can now release our bonds to specific assemblies / classes and have truly lightweight classes. Consider how pre-4.0 would have been done:

POCO through technology stack

Each layer would have involved some form of transformation from one type to another simply to avoid issues with the associated technology stack.

Consider the “new” way with .NET 4.0:

POCO through technology stack

Now we don’t have to do any transformation from one type to another because the same type is used all the way up the technology stack without any issues (except for the one described earlier).

So how was it done?

The following steps will guide you through the process:

1. Define our POCO classes according to our Data Model:

[POCO classes]

POCO Definition

[Data Model]

EF Data Model

2. Remove the Custom Tool from the DataMapping properties
(so that we can use POCO):

EFDM Custom Tool

Effect of removing EFDM Custom Tool

3. Define the Context Interface that will become the injection point in future references to the DAL:

    public interface IDiveLoggerContext
    {
        IObjectSet AccessTypes { get; }
        IObjectSet CertificationTypes { get; }
        IObjectSet DiveProfiles { get; }
        IObjectSet Divers { get; }
        IObjectSet DiveSites { get; }
        IObjectSet SurfaceTypes { get; }
        IObjectSet WaterBodyTypes { get; }
    }

And implement it

Implement Context Interface

4. In a WCF project define the Service Interface (we will not decorate the DataContracts as they are POCO):

namespace DiveLogger.Service
{
    [ServiceContract]
    public interface ILoggerService
    {
        [OperationContract]
        Diver GetDiver(int id);
    }
}
5. Create the CyclicReferencesAwareContractBehavior, CyclicReferencesAwareAttribute and ApplyCyclicDataContractSerializerOperationBehavior classes as described in Chabsters blog (WCF Cyclic references support). Obviously if there are no cyclic references in any of our entities, then chances are you will not need to put in this workaround for WCF 4.0.

Cyclic Reference Treatment Classes

And use it on the Service contract

Use CyclicReferencesAware attribute

Now the XmlSerialization can handle those pesky cyclic reference Navigation Properties and our WCF Service will work.

6. Utilize the Context Interface we created earlier to separate the DAL from the Service:

    public class LoggerService : ILoggerService
    {
        private IDiveLoggerContext m_context;

        public LoggerService()
        {
            Initialize(null);
        }

        internal LoggerService(IDiveLoggerContext i_context)
        {
            Initialize(i_context);
        }

        private void Initialize(IDiveLoggerContext i_context)
        {
            m_context = i_context ?? new DiveLoggerContext(UtilityFunctions.BuildAdoConnectionString(null));
        }

        public Diver GetDiver(int id)
        {
            if (id < 1 || id > 999)
                throw new ArgumentOutOfRangeException("Diver ID needs to be between 1 and 999", "id");

            IQueryable query = from diver in m_context.Divers
                                      .Include("CertificationTypes")
                                      .Include("DiveProfiles")
                                      .Include("DiveProfiles.DiveSite")
                                      .Include("DiveProfiles.WaterBodyType")
                                      .Include("DiveProfiles.AccessType")
                                      .Include("DiveProfiles.SurfaceType")
                                      where diver.Id == id
                                      select diver;
            Diver retVal = query.ToList().SingleOrDefault();
            return retVal;
        }
    }
7. In our Unit Test we can mock out the Context Interface instead of generating an actual instance:

    [TestMethod]
    public void TestGetSingleDiver()
    {
        // - ARRANGE -
        // Create the stub instance
        IDiveLoggerContext context = MockRepository.GenerateStub();

        // define/create dummy data
        int id = 500;
        string firstName = "Sherlock";
        string lastName = "Holmes";
        string title = "Mr.";
        IObjectSet divers = TestHelper.CreateDivers(id, firstName, lastName).AsObjectSet();

        // declare instance that we want to "retrieve"
        Diver individual;

        // Explicitly state how the stubs should behave
        context.Stub(stub => stub.Divers).Return(divers);

        // Create a real instance of the Servcie that we want to put under test, injecting the dependency in the constructor
        LoggerService service = new LoggerService(context);

        // - ACT -
        individual = service.GetDiver(id);
        // - ASSERT -
        // Make absoultely sure that the expected excption type was thrown
        Assert.IsNotNull(individual);
        // Make sure that the method was NOT called.
        context.AssertWasCalled(stub => { var temp = stub.Divers; });
    }

This will mean that we can get more realistic code-coverage on our Service:

Code Coverage

The following zip file contains all of the classes and code mentioned in the steps outlined previously:

Divelogger.zip

  • Share/Bookmark