#altnetseattle - REST Services

Below are the notes I made in the REST Architecture Session I helped kick off with Andrew.

  • RSS, ATOM, and such needed for better discovery.  i.e. there still is a need for some type of discovery.
  • Difficult is modeling behaviors in a RESTful way.  ??  Invoking some type of state against an object.  For instance in the case of a POST vs. a GET.  The GET is easy, comes back as is, but what about a POST, which often changes some state or something.
  • Challenge is doing multiple workflows with stateful workflows.  How does batch work.  Maybe model the batch as a resource.
  • Frameworks aren?t particularly part of REST, REST is REST.  But point argued that REST is modeled, or part of modeling a state machine of some sort? ?
  • Nothing is 100% reliable w/ REST ? comparisons drawn with TCP/IP.  Sufficient probability is made however for the communications, but the idea of a possible failure has to be built into the usage model of REST.
  • Ruby on Rails / RESTfully, and others used.  What were their issues, what do they do.  ATOM feeds, object serialized, using LINQ to XML w/ this.  No state machine libraries.
  • Idempotent areas around REST and single change POST changes are inherent in the architecture.
  • REST ? one of the constrained languages is for the interaction w/ the system.  Limiting what can be done on the resources.  - disagreement, there is no agreed upon REST verbs.
  • Sam Ruby ? RESTful services.  Expanded the verbs within REST/HTTP pushes you off the web.  Of the existing verbs POST leaves the most up for debate.
  • Robert Reem used Factory to deal with the POST to handle the new state.  The POST identifying what it just did by the return.
  • Different states are put into POST, so that new prospective verbs, without creating verbs for REST/HTTP can be used to advantage without breaking universal clients.
  • Biggest issue with REST services is their lack of state, yet it is also one of their biggest strengths.  What happens is that the client takes up the often onerous task of handling all state, state machines, and other extraneous resource management.  All the GETs, POSTs, DELETEs, INSERTs get all pushed into abstraction.  My 2 cents is that this in a way ends up pushing a huge proprietary burden onto the REST services often removing the point of REST to be simple and to the point.
  • WADL does provide discovery and some state control (sort of?)
  • Statement made, "WADL" isn't needed.  The JSON, XML, or other client side returned data handles this.

I then applied the law of 2 feet rule for myself and headed to finish up these notes, post to the Wiki, and figure out what I was going to do next.  For the original Wiki entry check it out here.

I will be adding more to this post with a subsequent post.  Please do feel free to post your thoughts and ideas about this, as I am sure everyone in the session will have more for elaboration.
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: Adron
Posted on: 4/11/2010 at 2:07 PM
Tags: ,
Categories: Events | Discussion Points or Ideas | Design Patterns
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

HighBall Part Duex (#4) Patterns

Here in part #4 I want to cover the final wire up I did to get the initial screens to show.  The other primary focus of this blog entry is to cover some of the architectural patterns behind what I have so far.  We haven't touched upon testing this yet, primarily because I'm stepping through wiring both Silverlight & WPF with these libraries for the first time.  I've done the WPF before, but not both.  Soon enough, I'll get back to good standard practice and get some tests done first.  But for now, here's the low down on wiring up Silverlight and the architectural patterns so far.

Architectural Patterns & Ideas

Dependency Injection

This is one of interesting parts of the application, at least to me.  For many the dependency injection is endlessly confusing, but it comes in immensely helpful in getting things loosely coupled and all wired up.  Because even when you decouple things, they do have to get wired up again - it's just the how that's important.  Below is an example of a presenter in the schedule module that uses constructor based dependency injection.  Dig it?  I'll have another follow up entry in the future about what and how Dependency Injection works, along with the respective Dependency Inversion, Inversion of Control, and all those other patterns.  For now, just now that this is how the view gets registered with the region that is responsible for displaying it when the application runs.

public class ScheduleViewAllPresenter : IModule
{
    private readonly IRegionViewRegistry regionViewRegistry;
 
    public ScheduleViewAllPresenter(IRegionViewRegistry registry)
    {
        regionViewRegistry = registry;
    }
 
    public void Initialize()
    {
        regionViewRegistry.RegisterViewWithRegion("HighBallMainRegion", typeof(ScheduleViewAllView));
    }
}

In the code snippet above you'll see in the initialize method that the view that is injected is registered to the particular region that it will be displayed in.  In the shell the view will be displayed in the region as shown below.

<Window x:Class="HighBall.Interface.Wpf.HighBallShell"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cal="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"
    Title="High Ball - WPF" >
    <ItemsControl Name="MainRegion" cal:RegionManager.RegionName="HighBallMainRegion" />
</Window>

Composite Modules

I've added a single module to the solution so far.  This module has two views & their respective presenters, which I'll cover in the section below.  The module is simply a project, loosely coupled, that will provide a view and the presentation logic for that view to be injected into the shell upon some application logic.

The module itself isn't so much a pattern but more an architectural piece of the application.  As I move forward on this project I'll add more modules to the solution as functionality is needed.  Each module will have an isolated, or mostly isolated, business use.  The first example that I have is the HighBall.Interface.Modules.ScheduleModule.  I'll be adding more, probably along these lines;  mileage tracking, vehicle inventory, driver check-in, driver route choice, etc.  Each having a particular part of functionality that will primarily be isolated to itself.

When the CAL is used within a development team the modules would most likely be split off to individual pairs in the case of Agile, or even entire teams.  In Agile parlance each module would be a number of user stories, or in the most simple form, a single user story.

View & Presenter, with no Model yet.

The view and presenter are where you get to see the Model View Presenter (MVP) first start to appear.  Eventually as I move forward there will be the model, and more elaboration on the view and presenter.  For now all we have is the view, which is just the xaml markup and the presenter which is responsible for registering the view in the registry, and initializing the view with a region that it would be displayed in.  As you can see above in the Dependency Injection example the presenter is very thin at this point.

So that summarizes the cut off point for my first basic release of HighBall.  Check out the code release, rant at me about deficiencies, and if you have any additional ideas or other elaborations you'd like to see please do comment.

Currently I'm researching how to put TDD into effect to build the presenters, views, and other composite pieces of this application.  My next entry will have several examples of unit tests that aren't currently included in this release.  Until then, happy hacking (or coding).

kick it on DotNetKicks.com
Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

TDD, Architecture and Testing Code in Isolation :: Part 3

Navigate back to Part 2 of this series of entries.

Ok, ok, ok, the other two parts where lean on the unit tests.  Now we get down to the mocking, faking, and testing.  The first two tests I wrote have to do with the UserListing Entity.  Once again, since we're in a situation were thing are generated by LINQ, I'm not really sure of a solid reason, or how, to write tests that fail first.  How would one do that for testing entities?  I'm not sure but here are my first two that run returning green lights.

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using MbUnit.Framework;
   4:  using UnitTest.Controller;
   5:  using UnitTest.Mocks;
   6:   
   7:  namespace DataAccessLayer.Unit.mbUnitTests
   8:  {
   9:      [TestFixture]
  10:      public class UserListing
  11:      {
  12:          [Test]
  13:          public void TestGetUserListingEntity()7
  14:          {
  15:              DateTime theDate = DateTime.Now.AddDays(-6);
  16:              var controller = new TsrUserListingController
  17:                                   {
  18:                                       DataContext = new MockDataContextWrapper(new ExampleMockDatabase())
  19:                                   };
  20:              IEnumerable<TsrUserListing> results = controller.GetTsrUserListing(theDate);
  21:              Assert.IsNotNull(results);
  22:          }
  23:   
  24:          [Test]
  25:          public void TestGetUserListingEntityCount()
  26:          {
  27:              DateTime theDate = DateTime.Now.AddDays(-6);
  28:              var controller = new TsrUserListingController
  29:                                   {
  30:                                       DataContext = new MockDataContextWrapper(new ExampleMockDatabase())
  31:                                   };
  32:              IEnumerable<TsrUserListing> results = controller.GetTsrUserListing(theDate);
  33:   
  34:              int count = 0;
  35:              foreach (TsrUserListing tsrUserListing in results)
  36:              {
  37:                  count += 1;
  38:              }
  39:              Assert.IsTrue(count == 3);
  40:          }
  41:      }
  42:  }

I guess I could write some tests to just throw the asserts, such as checking for a count that I know would be wrong, but why?  Anyone have notions on that I'd be keen to hear them because I honestly feel I'm missing something.  Then of course I am testing generated code, so maybe this is a reasonable expectation.  At this point I also made the same tests for the TmtUserListing since those classes would need the same tests for assurance.

First I had to add the fake tables and some mock objects to the table entities.  In the ExampleMockDatabase add the following TmtUserListing to the "CreateTables()" method.

   1:  protected override void CreateTables()
   2:  {
   3:      AddTable<TsrUserListing>();
   4:      AddTable<TmtUserListing>();
   5:  }Now that we have our table we can add the objects to it.  Add this code snippet to the end of the Populate method.
   6:   
   7:  var testTmtUserListing1 =
   8:      new TmtUserListing
   9:          {
  10:              UserId = Guid.NewGuid(),
  11:              UserName = "Test User", 
  12:              LoweredUserName = "test user",
  13:              IsAnonymous = false,
  14:              LastActivityDate = DateTime.Now.AddDays(-4),
  15:              MobileAlias = "test user"
  16:          };
  17:  var testTmtUserListing2 =
  18:      new TmtUserListing
  19:          {
  20:              UserId = Guid.NewGuid(),
  21:              UserName = "User Test",
  22:              LoweredUserName = "user test",
  23:              IsAnonymous = true,
  24:              LastActivityDate = DateTime.Now.AddMinutes(-23),
  25:              MobileAlias = "user test"
  26:          };
  27:  var testTmtUserListing3 =
  28:      new TmtUserListing
  29:          {
  30:              UserId = Guid.NewGuid(),
  31:              UserName = "John Doe",
  32:              LoweredUserName = "john doe",
  33:              IsAnonymous = true,
  34:              LastActivityDate = DateTime.Now.AddHours(-22),
  35:              MobileAlias = "john doe"
  36:          };
  37:   
  38:  GetTable<TmtUserListing>().Add(testTmtUserListing1);
  39:  GetTable<TmtUserListing>().Add(testTmtUserListing2);
  40:  GetTable<TmtUserListing>().Add(testTmtUserListing3);

I "suppose" we could have written the tests first, but as I've mentioned since it is mostly generated code this just doesn't seem as important to do.  I'm however, if you got em', looking for reasons and ways to write legitimate red light tests against this first.

Next I built out a controller specific to the TmtUserListing Entities.

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using DataAccessLayer;
   5:  using UnitTest.Interfaces;
   6:   
   7:  namespace UnitTest.Controller
   8:  {
   9:      public class TmtUserListingController
  10:      {
  11:          public IDataContextWrapper DataContext { get; set; }
  12:   
  13:          public IEnumerable<TmtUserListing> GetTmtUserListing(DateTime lastActivityDate)
  14:          {
  15:              IEnumerable<TmtUserListing> TmtUserListings = from TmtUserListing in DataContext.Table<TmtUserListing>()
  16:                                                            where TmtUserListing.LastActivityDate >= lastActivityDate
  17:                                                            select TmtUserListing;
  18:              return TmtUserListings;
  19:          }
  20:   
  21:          public IEnumerable<TmtUserListing> GetTmtUserListing()
  22:          {
  23:              IEnumerable<TmtUserListing> TmtUserListings = from TmtUserListing in DataContext.Table<TmtUserListing>()
  24:                                                            select TmtUserListing;
  25:              return TmtUserListings;
  26:          }
  27:      }
  28:  }

...and of course the tests.  Which sure took long enough eh?

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using MbUnit.Framework;
   4:  using UnitTest.Controller;
   5:  using UnitTest.Mocks;
   6:   
   7:  namespace DataAccessLayer.Unit.mbUnitTests
   8:  {
   9:      [TestFixture]
  10:      public class UserListing
  11:      {
  12:          [Test]
  13:          public void TestGetTsrUserListingEntity()
  14:          {
  15:              DateTime theDate = DateTime.Now.AddDays(-6);
  16:              var controller = new TsrUserListingController
  17:                                   {
  18:                                       DataContext = new MockDataContextWrapper(new ExampleMockDatabase())
  19:                                   };
  20:              IEnumerable<TsrUserListing> results = controller.GetTsrUserListing(theDate);
  21:              Assert.IsNotNull(results);
  22:          }
  23:   
  24:          [Test]
  25:          public void TestGetTsrUserListingEntityCount()
  26:          {
  27:              DateTime theDate = DateTime.Now.AddDays(-6);
  28:              var controller = new TsrUserListingController
  29:                                   {
  30:                                       DataContext = new MockDataContextWrapper(new ExampleMockDatabase())
  31:                                   };
  32:              IEnumerable<TsrUserListing> results = controller.GetTsrUserListing(theDate);
  33:   
  34:              int count = 0;
  35:              foreach (TsrUserListing tsrUserListing in results)
  36:              {
  37:                  count += 1;
  38:              }
  39:              Assert.IsTrue(count == 3);
  40:          }
  41:   
  42:          [Test]
  43:          public void TestGetTsrUserListingAllEntity()
  44:          {
  45:              var controller = new TsrUserListingController
  46:                                   {DataContext = new MockDataContextWrapper(new ExampleMockDatabase())};
  47:              IEnumerable<TsrUserListing> results = controller.GetTsrUserListing();
  48:              Assert.IsNotNull(results);
  49:          }
  50:   
  51:          [Test]
  52:          public void TestGetTsrUserListingAllEntityCount()
  53:          {
  54:              var controller = new TsrUserListingController
  55:                                   {DataContext = new MockDataContextWrapper(new ExampleMockDatabase())};
  56:              IEnumerable<TsrUserListing> results = controller.GetTsrUserListing();
  57:   
  58:              int count = 0;
  59:              foreach (TsrUserListing tsrUserListing in results)
  60:              {
  61:                  count += 1;
  62:              }
  63:              Assert.IsNotNull(count == 3);
  64:          }
  65:   
  66:          [Test]
  67:          public void TestGetTmtUserListingEntity()
  68:          {
  69:              DateTime theDate = DateTime.Now.AddDays(-6);
  70:              var controller = new TmtUserListingController
  71:                                   {
  72:                                       DataContext = new MockDataContextWrapper(new ExampleMockDatabase())
  73:                                   };
  74:              IEnumerable<TmtUserListing> results = controller.GetTmtUserListing(theDate);
  75:              Assert.IsNotNull(results);
  76:          }
  77:   
  78:          [Test]
  79:          public void TestGetTmtUserListingEntityCount()
  80:          {
  81:              DateTime theDate = DateTime.Now.AddDays(-6);
  82:              var controller = new TmtUserListingController
  83:                                   {
  84:                                       DataContext = new MockDataContextWrapper(new ExampleMockDatabase())
  85:                                   };
  86:              IEnumerable<TmtUserListing> results = controller.GetTmtUserListing(theDate);
  87:   
  88:              int count = 0;
  89:              foreach (TmtUserListing tmtUserListing in results)
  90:              {
  91:                  count += 1;
  92:              }
  93:              Assert.IsTrue(count == 3);
  94:          }
  95:   
  96:          [Test]
  97:          public void TestGetTmtUserListingAllEntity()
  98:          {
  99:              var controller = new TmtUserListingController
 100:                                   {
 101:                                       DataContext = new MockDataContextWrapper(new ExampleMockDatabase())
 102:                                   };
 103:              IEnumerable<TmtUserListing> results = controller.GetTmtUserListing();
 104:              Assert.IsNotNull(results);
 105:          }
 106:   
 107:          [Test]
 108:          public void TestGetTmtUserListingAllEntityCount()
 109:          {
 110:              var controller = new TmtUserListingController
 111:                                   {
 112:                                       DataContext = new MockDataContextWrapper(new ExampleMockDatabase())
 113:                                   };
 114:              IEnumerable<TmtUserListing> results = controller.GetTmtUserListing();
 115:   
 116:              int count = 0;
 117:              foreach (TmtUserListing tmtUserListing in results)
 118:              {
 119:                  count += 1;
 120:              }
 121:              Assert.IsTrue(count == 3);
 122:          }
 123:      }
 124:  }

We now have tests that assure us our Data Access Layer is getting and retrieving the appropriate entities etc. 

In forthcoming entries I'll be adding to this type of testing entry based on the current Assembler, Data Transfer Object, and Remote Facade Architecture that the team I'm working with has been building.  We're doing some interesting things that will provide us with an opportunity to really step into some oddball much needed unit test scenarios.

Also, if anyone actually reads my grand article - what's the best way to get a count of an IEnumerable list?  I've completely drawn a blank on what the best practice are for doing that.  Maybe I should return a Generics List back instead?  Blagh... anyway, a test is a test is a test - if it serves the function it will work.

References and extra info for this Triumvirate of Entries:

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: Adron
Posted on: 7/10/2008 at 7:13 AM
Tags: , , , , , , , , , , , , , , ,
Categories: How-To, Samples, and Such | Unit Testing
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (1) | Post RSSRSS comment feed

TDD, Architecture and Testing Code in Isolation :: Part 2

Navigate back to Part 1 of this series of entries.

The next steps I undertook are some of my various clean ups.  Create respective test classes for each of the pieces of the database that will have respective entities, methods, or objects to test.

I like to keep code clean, easy to read, and were it needs to be.  I hate code bloat, misplaced code sections, and above all I can't stand arbitrary pieces of using statements, random misuses of methods (such as ToString()) and other such things.  Luckily for me JetBrains Software created ReSharper.  So before going to far headlong into the tests I always run a few "Cleanup Code..." functions on my newly created files.

I usually just leave the cleanup code settings on full and click run.

The code already, with just the crude skeleton goes from this...

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using MbUnit.Framework;
   6:   
   7:  namespace DataAccessLayer.Unit.mbUnitTests
   8:  {
   9:      [TestFixture]
  10:      public class Users
  11:      {
  12:          [Test]
  13:          public void Test()
  14:          {
  15:              //
  16:              // TODO: Add test logic here
  17:              //
  18:          }
  19:      }
  20:  }

...to this...

using MbUnit.Framework;
   1:  namespace DataAccessLayer.Unit.mbUnitTests
   2:  {
   3:      [TestFixture]
   4:      public class Users
   5:      {
   6:          [Test]
   7:          public void Test()
   8:          {
   9:              //
  10:              // TODO: Add test logic here
  11:              //
  12:          }
  13:      }
  14:  }

Reason number eight gazillion that ReSharper RULEZ!  I almost forgot too, I need to have my Rhino Mock Library References.  If you don't have the Rhino Mock Library you can download it.  Generally I just put a folder in the solution, stick the DLL in it, and then browse to make a reference.

Now that we have clean test fixtures I'm going to run some green lights.  Green light tests that is, which is not in true TDD fashion.  The reason though is because this layer will be tests against a generated layer (the LINQ to SQL).  The generated layer doesn't really require a red light green light process, so I'm just going to write the bare minimum of green light tests against the layer.  Then when we go to the next layer, which WILL need to be red light green light I'll already have this layer tested appropriately. 

Before going any further and I forget another reference I'm grabbing the DAL Layer assembly.

Now that I've managed to not forget the references, which I've been working on doing, and I have the appropriate items in place.  The next step NOW is to get those green lights.  Off to the reckless abandon of TDD.  The first tests I write are simple, no frills, just to get and test the TsrUser and TmtUser Entities.

   1:  using System;
   2:  using MbUnit.Framework;
   3:  using Rhino.Mocks;
   4:   
   5:  namespace DataAccessLayer.Unit.mbUnitTests
   6:  {
   7:      [TestFixture]
   8:      public class Users
   9:      {
  10:          [Test]
  11:          public void TestTsrUserEntity()
  12:          {
  13:              Guid newUserId = Guid.NewGuid();
  14:              TsrUser tsrUser = MockRepository.GenerateStub<TsrUser>();
  15:              tsrUser.UserId = newUserId;
  16:              Assert.AreEqual(tsrUser.UserId, newUserId);
  17:          }
  18:   
  19:          [Test]
  20:          public void TestTmtUserEntity()
  21:          {
  22:              Guid newUserId = Guid.NewGuid();
  23:              TmtUser tmtUser = MockRepository.GenerateStub<TmtUser>();
  24:              tmtUser.UserId = newUserId;
  25:              Assert.AreEqual(tmtUser.UserId, newUserId);
  26:          }
  27:      }
  28:  }

Next, hit up the User Lists derived from the views.  This is where the mocking gets truly interesting.  The above tests, while they help, really don't do much of anything.  Next what I need is a way to mock out the DataContext Class, which doesn't have an interface.  This is a slight issue, but just requires a little manual coding to get a good mock going.  Since I knew I'd be using this for multiple testing projects I've created a completely new project to reference.  Since I'm not always creative I'm naming it "UnitTest" and then will name the files respectively.

I also found a bit of code specifically for mocking the DataContext over at Andrew Tokeley's Blog on Mocking LINQ to SQL DataContext.  I've snagged it and have altered it for the particular project.  Make sure to give dibs to Andrew!  Below are the modified interfaces and the respective classes.  Make sure to add a reference to the DAL for the project too.  Then add the files listed below in the screen shot.

IDataContextWrapper Interface

   1:  using System;
   2:  using System.Collections.Generic;
   3:   
   4:  namespace UnitTest.Interfaces
   5:  {
   6:      public interface IDataContextWrapper : IDisposable
   7:      {
   8:          List<T> Table<T>() where T : class;
   9:          void DeleteAllOnSubmit<T>(IEnumerable<T> entities) where T : class;
  10:          void DeleteOnSubmit<T>(T entity) where T : class;
  11:          void InsertOnSubmit<T>(T entity) where T : class;
  12:          void SubmitChanges();
  13:      }
  14:  }

IMockDatabase Interface

   1:  using System;
   2:  using System.Collections;
   3:  using System.Collections.Generic;
   4:   
   5:  namespace UnitTest.Interfaces
   6:  {
   7:      public interface IMockDatabase
   8:      {
   9:          Dictionary<Type, IList> Tables { get; set; }
  10:      }
  11:  }

MockDatabase Class

   1:  using System;
   2:  using System.Collections;
   3:  using System.Collections.Generic;
   4:   
   5:  namespace UnitTest.Mocks
   6:  {
   7:      /// <summary>
   8:      /// Abstract Template class that represents our in memory database. We can create different implementations of this class that contain different
   9:      /// tables and data.
  10:      /// </summary>
  11:      public abstract class MockDatabase
  12:      {
  13:          protected MockDatabase()
  14:          {
  15:              InitializeDataBase();
  16:          }
  17:   
  18:          public Dictionary<Type, IList> Tables { get; set; }
  19:   
  20:          private void InitializeDataBase()
  21:          {
  22:              Tables = new Dictionary<Type, IList>();
  23:              CreateTables();
  24:              PopulateTables();
  25:          }
  26:   
  27:          protected abstract void CreateTables();
  28:          protected abstract void PopulateTables();
  29:   
  30:          protected void AddTable<T>()
  31:          {
  32:              var table = new List<T>();
  33:              Tables.Add(typeof (T), table);
  34:          }
  35:   
  36:          protected List<T> GetTable<T>()
  37:          {
  38:              return (List<T>) Tables[typeof (T)];
  39:          }
  40:      }
  41:  }

MockDatabaseContextWrapper Wrapper Class

   1:  using System.Collections.Generic;
   2:  using UnitTest.Interfaces;
   3:   
   4:  namespace UnitTest.Mocks
   5:  {
   6:      /// <summary>
   7:      /// A linq to sql wrapper class. This is a mock implementation of IDataContextWrapper
   8:      /// that works directly with an in memory version of a database 
   9:      /// </summary>
  10:      public class MockDataContextWrapper : IDataContextWrapper
  11:      {
  12:          private readonly MockDatabase _mockDatabase;
  13:   
  14:          public MockDataContextWrapper(MockDatabase database)
  15:          {
  16:              _mockDatabase = database;
  17:          }
  18:   
  19:          #region IDataContextWrapper Members
  20:   
  21:          public List<T> Table<T>() where T : class
  22:          {
  23:              return (List<T>) _mockDatabase.Tables[typeof (T)];
  24:          }
  25:   
  26:          public void DeleteAllOnSubmit<T>(IEnumerable<T> entities) where T : class
  27:          {
  28:              foreach (T entity in entities)
  29:              {
  30:                  Table<T>().Remove(entity);
  31:              }
  32:          }
  33:   
  34:          public void DeleteOnSubmit<T>(T entity) where T : class
  35:          {
  36:              Table<T>().Remove(entity);
  37:          }
  38:   
  39:          public void InsertOnSubmit<T>(T entity) where T : class
  40:          {
  41:              Table<T>().Add(entity);
  42:          }
  43:   
  44:          public void SubmitChanges()
  45:          {
  46:          }
  47:   
  48:          public void Dispose()
  49:          {
  50:          }
  51:   
  52:          #endregion
  53:      }
  54:  }

DataContextWrapper Wrapper Class

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Data.Linq;
   4:  using System.Linq;
   5:  using UnitTest.Interfaces;
   6:   
   7:  namespace UnitTest
   8:  {
   9:      /// <summary>
  10:      /// A linq to sql wrapper class for the Datacontext object. This is the real implementation of IDataContextWrapper
  11:      /// that works directly with a database 
  12:      /// </summary>
  13:      /// <typeparam name="T"></typeparam>
  14:      public class DataContextWrapper<T> : IDataContextWrapper where T : DataContext, new()
  15:      {
  16:          private readonly T db;
  17:          private bool _disposed;
  18:   
  19:          public DataContextWrapper()
  20:          {
  21:              Type t = typeof (T);
  22:              db = (T) Activator.CreateInstance(t);
  23:          }
  24:   
  25:          public DataContextWrapper(string connectionString)
  26:          {
  27:              Type t = typeof (T);
  28:              db = (T) Activator.CreateInstance(t, connectionString);
  29:          }
  30:   
  31:          #region IDataContextWrapper Members
  32:   
  33:          public List<TableName> Table<TableName>() where TableName : class
  34:          {
  35:              var table = (Table<TableName>) db.GetTable(typeof (TableName));
  36:   
  37:              return table.ToList();
  38:          }
  39:   
  40:          public void DeleteAllOnSubmit<Entity>(IEnumerable<Entity> entities) where Entity : class
  41:          {
  42:              db.GetTable(typeof (Entity)).DeleteAllOnSubmit(entities);
  43:          }
  44:   
  45:          public void DeleteOnSubmit<Entity>(Entity entity) where Entity : class
  46:          {
  47:              db.GetTable(typeof (Entity)).DeleteOnSubmit(entity);
  48:          }
  49:   
  50:          public void InsertOnSubmit<Entity>(Entity entity) where Entity : class
  51:          {
  52:              db.GetTable(typeof (Entity)).InsertOnSubmit(entity);
  53:          }
  54:   
  55:          public void SubmitChanges()
  56:          {
  57:              db.SubmitChanges();
  58:          }
  59:   
  60:          public void Dispose()
  61:          {
  62:              Dispose(true);
  63:              GC.SuppressFinalize(this);
  64:          }
  65:   
  66:          #endregion
  67:   
  68:          private void Dispose(bool disposing)
  69:          {
  70:              if (_disposed)
  71:                  return;
  72:   
  73:              if (disposing)
  74:              {
  75:                  db.Dispose();
  76:              }
  77:   
  78:              _disposed = true;
  79:          }
  80:      }
  81:  }

ExampleMockDatabase Class

   1:  using System;
   2:  using DataAccessLayer;
   3:   
   4:  namespace UnitTest.Mocks
   5:  {
   6:      /// <summary>
   7:      /// This is an actual implementation of our database containing specific tables and data.
   8:      /// </summary>
   9:      public class ExampleMockDatabase : MockDatabase
  10:      {
  11:          protected override void CreateTables()
  12:          {
  13:              AddTable<TsrUserListing>();
  14:          }
  15:   
  16:          protected override void PopulateTables()
  17:          {
  18:              var testTsrUserListing1 =
  19:                  new TsrUserListing
  20:                      {
  21:                          UserId = Guid.NewGuid(),
  22:                          UserName = "Test User",
  23:                          LoweredUserName = "test user",
  24:                          IsAnonymous = false,
  25:                          LastActivityDate = DateTime.Now.AddDays(-4),
  26:                          MobileAlias = "test user"
  27:                      };
  28:              var testTsrUserListing2 =
  29:                  new TsrUserListing
  30:                      {
  31:                          UserId = Guid.NewGuid(),
  32:                          UserName = "User Test",
  33:                          LoweredUserName = "user test",
  34:                          IsAnonymous = true,
  35:                          LastActivityDate = DateTime.Now.AddMinutes(-23),
  36:                          MobileAlias = "user test"
  37:                      };
  38:              var testTsrUserListing3 =
  39:                  new TsrUserListing
  40:                      {
  41:                          UserId = Guid.NewGuid(),
  42:                          UserName = "John Doe",
  43:                          LoweredUserName = "john doe",
  44:                          IsAnonymous = true,
  45:                          LastActivityDate = DateTime.Now.AddHours(-22),
  46:                          MobileAlias = "john doe"
  47:                      };
  48:   
  49:              GetTable<TsrUserListing>().Add(testTsrUserListing1);
  50:              GetTable<TsrUserListing>().Add(testTsrUserListing2);
  51:              GetTable<TsrUserListing>().Add(testTsrUserListing3);
  52:          }
  53:      }
  54:  }

CustomerController Class

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using DataAccessLayer;
   5:  using UnitTest.Interfaces;
   6:   
   7:  namespace UnitTest.Controller
   8:  {
   9:      public class TsrUserListingController
  10:      {
  11:          public IDataContextWrapper DataContext { get; set; }
  12:   
  13:          public IEnumerable<TsrUserListing> GetTsrUserListing(DateTime lastActivityDate)
  14:          {
  15:              IEnumerable<TsrUserListing> tsrUserListings = from tsrUserListing in DataContext.Table<TsrUserListing>()
  16:                                                            where tsrUserListing.LastActivityDate >= lastActivityDate
  17:                                                            select tsrUserListing;
  18:              return tsrUserListings;
  19:          }
  20:   
  21:          public IEnumerable<TsrUserListing> GetTsrUserListing()
  22:          {
  23:              IEnumerable<TsrUserListing> tsrUserListings = from tsrUserListing in DataContext.Table<TsrUserListing>()
  24:                                                            select tsrUserListing;
  25:              return tsrUserListings;
  26:          }
  27:      }
  28:  }

Now that we have the database fake/mock - whatever one wants to call it - we're ready for some tests.  So stay tuned, I'll have it up tomorrow.

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList