ASP.NET MVC Scorecard Web Application - Part 1

There have been a lot of requests for MVC based scorecards, so I am going to kick off a new series of wiring up an MVC scorecard site.  This first part will simply cover setting up the basic site and skeleton framework using the default ASP.NET MVC Project.

Start off by starting a new ASP.NET MVC Project.  Since I will be creating tests for this walk through, be sure to add a unit test project also.  I am just using the default MS-test libraries for now, but feel free to apply whatever test framework you would like.

To create additional views and controllers we'll add a unit test for a new controller.  I will name this new controller ScorecardController, so I have added a test file called ScorecardControllerTest.cs.  The first test is just the standard action for the appropriate method actions and returning the view, as follows.  I added a similar test for the Index method also.

[TestClass]
public class ScorecardControllerTest
{
    [TestMethod]
    public void Scorecard()
    {
        ScorecardController scorecardController = new ScorecardController();
        var result = scorecardController.Scorecard() as ViewResult;
        Assert.IsNotNull(result);
    }
 
    [TestMethod]
    public void Index()
    {
        ScorecardController scorecardController = new ScorecardController();
        var result = scorecardController.Index() as ViewResult;
        Assert.IsNotNull(result);
    }
}

Once the skeleton implementation is made to get green lights on these tests, a controller will be created with the following code.

public class ScorecardController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
 
    public ActionResult Scorecard()
    {
        return View();
    }
}

At this point I need to create some tests for what is expected in the view, but I will get to that once a bit more of the skeleton of the site is done.  As soon as I wrote these tests, based on where they are located in my folder structure I decided that I need to do a quick refactor of the name.  Having a Scorecard/Scorecard path just seemed stupid, so I renamed the Scorecard.aspx to Display.aspx and changed the method name appropriately.  If you are following along, the subsequent code will be using the renamed page/method, etc.

The next thing I wanted to do was to get the view coming up appropriately, so first things first, new tests.

[TestMethod]
public void ScorecardViewExists()
{
    ScorecardController scorecardController = new ScorecardController();
    var result = scorecardController.Display() as ViewResult;
    Assert.AreEqual("Display", result.ViewName);
}

First of course it fails, but with the appropriate change shown, all runs green again.

public ActionResult Display()
{
    return View("Display");
}

So after this I added the following tests, controller actions, and views.

[TestMethod]
public void Select()
{
    ScorecardController scorecardController = new ScorecardController();
    var result = scorecardController.Select() as ViewResult;
    Assert.IsNotNull(result);
}
 
[TestMethod]
public void SelectViewNamed()
{
    ScorecardController scorecardController = new ScorecardController();
    var result = scorecardController.Select() as ViewResult;
    Assert.AreEqual("Select", result.ViewName);
}
 
[TestMethod]
public void IndexViewNamed()
{
    ScorecardController scorecardController = new ScorecardController();
    var result = scorecardController.Index() as ViewResult;
    Assert.AreEqual("Index", result.ViewName);
}

After that I edited the CSS so I could get a better feel to the site relative to what I am working toward.  I will leave you to decide what you want to do with the CSS & such yourself.  One of these days I will be graphic artists worthy, for now I am just happy with a decent looking layout and reasonable colors. ;)

When I was done my Solution Explorer looked like this.

Last I added the following to the Site.Master page for appropriate linkages.  This spot is located in the menucontainer section of the page.

<div id="menucontainer">
    <ul id="menu">
        <li>
            <%= Html.ActionLink("Home", "Index", "Home")%></li>
        <li>
            <%= Html.ActionLink("About", "About", "Home")%></li>
        <li>
            <%= Html.ActionLink("Scorecard", "Display", "Scorecard") %></li>
    </ul>
</div>

When I run the app I now have a basic skeleton and the initial pages I am going to work with.  Next steps coming soon.

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

Posted by: Adron
Posted on: 12/29/2009 at 5:05 AM
Tags: , , , , , ,
Categories: How-To, Samples, and Such | Unit Testing
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (6) | Post RSSRSS comment feed

Some Agile Ramblings Around TDD

Got a question recently, from multiple people regarding test driven development.  One simply asked why TDD is not the standard (as in way to develop).  Another person asked me how spending more time writing tests speeds things up over time.  Well, I will cover a bit of that real quick and try to explain my 2 cents on the whole practice.

What is test driven development?  The practice entails developing a test, which fails (because obviously you?ve written it first).  Once you have written the test you then create the initial skeleton that will get that test to pass.  Here is a crude a basic example.  I am using NUnit for these examples, so if you don't have it, go get it or whatever your test framework of choice is.

First you write the test which will fail.  Also known as getting the "red light".

    [TestFixture]
    public class RamblingsTests
    {
        [Test]
        public void InstantiateRambling()
        {
            Rambling rambling = new Rambling("I'm talking here and all.");
            Assert.IsNotNull(rambling);
        }
    }

Next you flesh out the actual class, which if you have the appropriate refactoring tools and awesome stuff like ReSharper takes about 5 seconds ? literally.

    public class Rambling
    {
        public Rambling(string s)
        {
            throw new NotImplementedException();
        }
    }

Now when we run this we can see it fail.

Of course to get the test to pass, we simply can get rid of the exception being thrown!  So I do that next and we get a nice green light.

Now the class is pretty useless, so I will add a simple feature next.  But I will follow true TDD style practice.  I will not just whack some code onto the object, we'll immediately lose the effectiveness of TDD if we just break the process and start cramming code, no matter how small, into the class we've just created.  So I have a test instead;

    [Test]
    public void ConfirmRamblingIsRambled()
    {
        Rambling rambling = new Rambling("More rambling is occurring here.");
        Assert.IsNotEmpty(rambling.Text);
    }

Running that fails so immediately I will add the code to get a good green light.

    public class Rambling
    {
        public Rambling(string s)
        {
            Text = s;
        }
 
        public string Text { get; set; }
    }

Now there is a class, that can be instantiated by passing a string parameter in, and the parameter is then assigned to the Text property which can be retrieved after instantiation.

What else do we have?  We also have immediate regression if any changes are made.  We have the confidence that we know each part works & that nothing got fat fingered in.  Now let us imagine we had to do a bit of editing to the Rambling instantiation so that some business logic occurs after the text is passed in as a parameter.  In other words, we'll imagine we have a refactor or change requirement to make.

Let us say we wanted to check and make sure there was always going to be at least a period on the end of any Ramble's Text property.  Now of course that is super easy but don't go messing the flow up and adding the functionality yet, first add a test.

        [Test]
        public void ConfirmRambleHasPunctuation()
        {
            Rambling rambling = new Rambling("Another rambling ramble.");
            Assert.IsTrue(rambling.Text.EndsWith("."));
        }
 
        [Test]
        public void ConfirmRambleGetsPunctuation()
        {
            Rambling rambling = new Rambling("Another typing rambling ramble");
            Assert.IsTrue(rambling.Text.EndsWith("."));
        }

I've written two tests above.  It might seem silly or excessive in this scenario, but think if this was some serious heavy duty business logic that had all types of processing going on.  You would want to check more than just one or two scenarios and at least cover most of what one might think up.  Of course Quality Assurance hits the outliers, but no developer should ever be submitting code to QA that has stupid bugs ? ESPECIALLY if it can be resolved via TDD or even test after development.  EVERYONE should be writing tests for their code ? even if they end up not quite meeting the standards of isolated, testable units ? write tests!  When you get into the practice, getting them into isolated testable units gets easier and easier.  So we've got two tests now to confirm that the Text Property will end with a period even if the instantiation string parameter isn't passed with any.

Here is the addition to the code to get green lights on both tests.

    public class Rambling
    {
        public Rambling(string s)
        {
            if(!s.EndsWith("."))
                s += ".";
            Text = s;
        }
 
        public string Text { get; set; }
    }

Now we have 4 green lights.  Life is good and our code is tested.

I have a really hard time why some developers seem to just not test their code.  Sometimes it is the management, sometimes other work environment issues, but as for core functional legitimate reasons I can't find any to not write unit tests.

Some people have brought up not needing to write tests for code that works based solely off of configuration settings, such as from a Web.Config, and I can agree with that.  At most, write a test to verify you're prepared for a configuration setting not being available that you think might be.  Beyond that, no point in going over ground already traversed - one would hope - with thorough QA and respective resources.

Time Consumption Issues

Now as some of you, especially if you worked through these examples, or even wrote up some of your own you will have noticed that it took more time than if you just wrote the code.  Yeah, on this insanely easy, kindergarten example it did take more time.  But seriously, think about it for a minute, when you're in the heat of coding (especially if you aren't paired up) will you actually catch each little mistake?  Maybe during the build of the code, maybe afterwards you might.  Will you actually not miss every single detail and be absolutely sure you get every business rule and detail into the logic?  I would not put trust in anyone to do so.  After 12+ years of software development, I have yet to see someone write code well if they aren't testing the hell out of it at the same time.  The cleanest, fastest, most well organized code I have ever seen has come from developers working within the TDD mindset & process.  The only individuals I have ever seen produce better code are developers that pair program.

?but I am not going to go into the pair programming paradigm, that is for another entry another day.

TDD drastically increases the quality and integrity of your code.  With higher quality you do not have to take as many steps to refactor, you do not worry as much about quality once the practice is in your head.  The quality comes from the refactorings you do commit and improvements only go up from there.  Using TDD you will eventually find, no matter how hard headed one is in the beginning, that you will vastly increase your code quality and significantly decrease you're actual post writing QA bugs, rewrites, and all those other assorted annoyances than a good developer should keep minimized.

As for the project planners, it might seem like it takes a while to write tests, but when you see those QA cycles shorten, the code quality increase, and eventually ? yes, I promise ? the legitimate velocity of development increase and then ? drum roll please ? sustain, you'll be thankful that you or your developers in the team are practicing TDD.

I personally, can barely imagine a world in which I skip tests.  I've honestly tried in the past couple years a couple times to stop testing ? just to have a flashback to when I started coding ya know ;) - and have ended up providing a prime example why you do NOT skip unit testing.  Unfortunately I wasn't prepared for the first failure from not testing, and it took the second "I command you not to test cuz it's ruining my project plan" bull shit to be prepared to basically test anyway and then show how the non-tested code doesn't hold up against the unit tested code base.

There are of course pitfalls, and a lot of them, as with anything and developers have to work diligently to avoid them.  At some time in the future I'll elaborate on those also.  For now I'm going to jump from this and into my thoughts on why some environments do not test still, even with the ever growing mountain of evidence that you're insane not to.

Fear and Courage

Unfortunately most development teams have, if they are EXTREMELY lucky, at least one super motivated and above average developer.  Once in a very rare time a team will have 2 or more.  But if the team has average, weak, or super strong developers no matter testing should be done.  Even if one is just out of college and not really a strong developer yet, they can still take the torch and push for good practices.  This is where the big question comes for any developer no matter what level ? do they have the courage?  The fear often overrides one's ability to step up and get testing put into practice among a team.  Above all, step up and have the courage.

Anyway, that's all the writing I have for the topic right now, got some #strangelovelive to watch and some code to hack out.  Hope this provides some insight into the issues & problems in getting good TDD practice kick started in a development environment among a team.  I'll definitely have a lot more to say soon as I've routinely been joining more and more conversations regarding the Agile and specifically the TDD practice.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: adron
Posted on: 7/10/2009 at 11:01 PM
Tags: , , ,
Categories: How-To, Samples, and Such | Unit Testing
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Excel Spreadsheet Tests :: Tip o' The Day

While working through some of the Excel scenarios lately I've come upon some more ways to test Excel.

Create an Excel Application instance with the default workbook.  Doing this will drastically speed up your tests.  Do this in the fixture setup & assign it to a property of the test class.  This way, no more startup and tear down of the Excel object for each test.

public Application ExcelApplication { get; set; }
 
[TestFixtureSetUp]
public void CreateExcelAppAppropriately()
{
    ExcelApplication = new Application();
    ExcelApplication.Workbooks.Add(Type.Missing);
    ExcelApplication.Visible = true;
}

That will give you a good kick start when you end up with a few dozen or more tests.  Starting up and killing the Excel Instance on each test can be brutal in overall performance.  For the shutdown of the tests, as long as you have clean code and don?t have odd Excel threads or something running off everywhere, the fixture shutdown can be as simple as below.

        [TestFixtureTearDown]
        public void QuitExcelAppAppropriately()
        {
            foreach (Workbook workbook in ExcelApplication.Workbooks)
            {
                workbook.Close(false, false, Type.Missing);
            }
            ExcelApplication.Quit();
        }

One other thing I like to do is add a boolean value that sets the Excel instance to stay visible and not close after the tests.  I create a private bool and then set it in any test I?m currently working with.  When I?m done I just remove the assignment and let it default to false.  This way the Excel instance doesn?t stay open for the build & tests on the build server.

private bool reviewExcelPostTests;
 
[TestFixtureTearDown]
public void QuitExcelAppAppropriately()
{
    if (reviewExcelPostTests)
        return;
 
    foreach (Workbook workbook in ExcelApplication.Workbooks)
    {
        workbook.Close(false, false, Type.Missing);
    }
    ExcelApplication.Quit();
}

That's it for my Excel tips today, I'll have some more coming in the near future.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: adron
Posted on: 6/28/2009 at 5:00 PM
Tags: , , ,
Categories: Tip o' The Day | Unit Testing | How-To, Samples, and Such
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Simian Satasin Asynchronous Calls

All I wanted was an asynchronous WebClient call.  What do I get?  Tons of dead links in MSDN, tons of pure crap of non working code all over the net.  Then I realized I needed to search for silverlight AND asynchronous instead of just asynchronous.  Anyway I finally found some legit code snippets and put together this simple test.  The story goes like this...

Here's a little test for getting asynchronous calls up and running, and tested.  Keep in mind long tests that take place over the network or that will introduce extensive latency should NOT be part of a CI build.  If anything set these into a separate build that can run over a period of time to assure integrity and that the services are up, but seriously, don't add them to a CI build.  I've seen enough of these, and it is VERY destructive to productive development.  No really, did I point this out yet, do NOT add these to a standard CI build.  K - thx.

With that warning, here's a way to test some services over REST.

   1:      [TestClass]
   2:      public class AsyncTest
   3:      {
   4:          private XDocument doc;
   5:   
   6:          [TestMethod]
   7:          public void TestMethod1()
   8:          {
   9:              string baseUri = "http://twitter.com/statuses/public_timeline.xml";
  10:              var svc = new WebClient();
  11:              svc.DownloadStringCompleted += svc_DownloadStringCompleted;
  12:              svc.DownloadStringAsync(new Uri(baseUri));
  13:   
  14:              Thread.Sleep(1000);
  15:              Assert.IsNotNull(doc);
  16:              XDocument docTest = new XDocument();
  17:              Assert.IsInstanceOfType(doc, docTest.GetType());
  18:          }
  19:   
  20:          private void svc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
  21:          {
  22:              doc = XDocument.Parse(e.Result);
  23:          }
  24:      }

Create a variable that the handler will assign a value to, it doesn't really matter what it assigns as long as it proves the handler executed.  Of course, if you're looking for a particular bit of code or a property you would want to test for that, but otherwise the primary concern is to test that it fired appropriately and didn't cause an explosion of some type.

Next create the method that initiates the call and wire up the event handler to the event.  Now when you execute the method, which I've left as the default lame name of TestMethod1, you should get a positive test.  The big question for this test is, "Will the REST service return in less than a second?"  If it takes longer you need to add to the Thread.Sleep(X) method.

There is of course all types of issue with this particular test.  Isolation is broken, it breaches boundaries, yadda yadda yadda yadda.  The point is, you get a test that can verify that a service is up, and that it responds with something.  As an extra kicker you can even verify that the service is responding within a certain threshold of time since a Thread.Sleep method is used.  If it fails because the time isn't enough, you would know you need to do something about the performance.

Either way, good luck on testing these, if you have any other ideas on legit ways to test services like these, please pop a comment on this entry.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: adron
Posted on: 2/20/2009 at 7:07 AM
Tags: , ,
Categories: How-To, Samples, and Such | Unit Testing
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Unit Testing Microsoft's Way? :: Tip o' The Day

I really don't get the complexity Microsoft has put into their testing framework.  The basic testing class that one gets looks like this.

   1:  using System;
   2:  using System.Text;
   3:  using System.Collections.Generic;
   4:  using System.Linq;
   5:  using Microsoft.VisualStudio.TestTools.UnitTesting;
   6:   
   7:  namespace PipServices.Tests
   8:  {
   9:      /// <summary>
  10:      /// Summary description for UnitTest1
  11:      /// </summary>
  12:      [TestClass]
  13:      public class UnitTest1
  14:      {
  15:          public UnitTest1()
  16:          {
  17:              //
  18:              // TODO: Add constructor logic here
  19:              //
  20:          }
  21:   
  22:          private TestContext testContextInstance;
  23:   
  24:          /// <summary>
  25:          ///Gets or sets the test context which provides
  26:          ///information about and functionality for the current test run.
  27:          ///</summary>
  28:          public TestContext TestContext
  29:          {
  30:              get
  31:              {
  32:                  return testContextInstance;
  33:              }
  34:              set
  35:              {
  36:                  testContextInstance = value;
  37:              }
  38:          }
  39:   
  40:          #region Additional test attributes
  41:          //
  42:          // You can use the following additional attributes as you write your tests:
  43:          //
  44:          // Use ClassInitialize to run code before running the first test in the class
  45:          // [ClassInitialize()]
  46:          // public static void MyClassInitialize(TestContext testContext) { }
  47:          //
  48:          // Use ClassCleanup to run code after all tests in a class have run
  49:          // [ClassCleanup()]
  50:          // public static void MyClassCleanup() { }
  51:          //
  52:          // Use TestInitialize to run code before running each test 
  53:          // [TestInitialize()]
  54:          // public void MyTestInitialize() { }
  55:          //
  56:          // Use TestCleanup to run code after each test has run
  57:          // [TestCleanup()]
  58:          // public void MyTestCleanup() { }
  59:          //
  60:          #endregion
  61:   
  62:          [TestMethod]
  63:          public void TestMethod1()
  64:          {
  65:              //
  66:              // TODO: Add test logic    here
  67:              //
  68:          }
  69:      }
  70:  }

After clean up and removal of all the using statements and such that one does not need to start writing test, the class looks like this.

   1:  using Microsoft.VisualStudio.TestTools.UnitTesting;
   2:   
   3:  namespace PipServices.Tests
   4:  {
   5:      [TestClass]
   6:      public class UnitTest1
   7:      {
   8:          [TestMethod]
   9:          public void TestMethod1()
  10:          {
  11:          }
  12:      }
  13:  }

I'd love to know what the mentality was behind all that other stuff being added.

After the cleanup there is 13 lines of code versus 70.  The intention of unit tests is to be simple, straight forward, and effectively explain via code what the functional code does.  So why all the extra deluge of mess?  Also the excessive comments are not needed, the test itself needs to provide the description of the code functionality.  If the test doesn't do this it isn't a very good test.  If there is a bunch of documentation describing what the test does it absolutely isn't that useful of a test.  The likelihood that the test is not done in isolation increases exponentially when there is comments and such, and every time I see them I just shrug at what usually is a useless test.  I don't quit get that, but would be happy if anyone could add to the reasoning (or know of any good links that might explain).

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: adron
Posted on: 12/14/2008 at 10:25 AM
Tags: ,
Categories: Just Stuff | Rants | Unit Testing
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (2) | Post RSSRSS comment feed

Stand Up, SCRUM, or Some Other Name - Pt. 3 - Super Day

Yesterday was rough going, mainly just because there was so many topics to cover.  Today I hope to nail a ton more functional code segments, requirements, and get some unit tests in my work.

Yesterday

  • Finished clarification of the task list and working to find the priorities for this iteration.
  • Met to clarify design goals and functional requirements for new features.

Today

  • Core focus will be on functional requirements and getting the respective unit tests, preferably via TDD for the interface based controller and presenter code.  I'll be happy with test after for the UI elements since they're all COM Interop.  i.e.,  today is code day.

Tomorrow

  • Continue focus on functional specifications and respective tests.

Road Blocks & Risks

  • Continued - Time constraints have all but eliminated efforts to research or implement a proof around the PIAB, limiting our exception handling, logging, and other cross cutting concerns we need to have in place.
  • Continued - The IoC and DI architecture points have not been clarified.  The more UI work we do without these pieces in place the more tightly coupled, untested, and unworkable refactor efforts will be in the future.
  • Continued - Significant risks include; lack of significant code coverage from unit tests, unclear way for testing the upper layers of Excel/UI functionality.
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

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

Just a few examples here.  First we'll setup the basic architecture from the lowest common denominator - the database - bounce up to the first layer, and test in isolation and test in integration.  These examples are simply the easiest ways to test the basic data and data access layer using Stubs, Mocks, and general unit test practices.

First off here are the pieces of the architecture that you'll NEED regardless.  No real coding in this entry (except for the T-SQL), just setting up the solution to put the tests in and have the initial database architecture setup.  The part 2 entry will have more on the testing, and part 3 will have actual functional code tests and implementations - after all, I'm working this up in a test driven development mentality - "mostly".

The Beginning

Setup the following projects within a new VS.NET solution.  I broke out the projects as you see below. (Click to see the larger image)

I like to keep my unit and integration tests separate so that they're easy to include or exclude from a continuous integration build.  Because really, the integration tests aren't generally going to work in a regular build.  Unless of course you've scripted out some serious steps such as "Create a Setup MSI" and "install the software and run" etc.  Which in my mind, just seems a bit out of line with the build process.  Not to even mention extremely time consuming.  I however think that a good solid and separate CI build of the respective setup project should be kept in a different solution that when it does alter can have a build process and either an automated integration test run or have the integration tests manually run.  Either way, they get run, but in my humble opinion shouldn't be run during the regular CI build of the working solution.

If you don't have mbUnit installed, go grab a copy over at www.mbunit.com.

The next thing I did is setup the databases.  I have some odd requirements for the particular database schema and segmentation of various databases for the application components.  The Grand Central Database is used for the security, membership, roles, etc, the other databases are used for each of the application "components".  Each of these "component" databases I'll refer to as either "component" or "tsr" or "tmt" respectively.  These "component" databases I've setup for use once a user is authenticated.  So each of these databases has a Users Table that has a UserId Column that will be used for relating the respective user that has access to the particular component.

First I setup the tables:

tmtUsers

   1:  /****** Object:  Table [dbo].[tmtUsers]    Script Date: 07/06/2008 01:27:07 ******/
   2:  IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tmtUsers]') AND type in (N'U'))
   3:  DROP TABLE [dbo].[tmtUsers]
   4:  GO
   5:  /****** Object:  Table [dbo].[tmtUsers]    Script Date: 07/06/2008 01:27:07 ******/
   6:  SET ANSI_NULLS ON
   7:  GO
   8:  SET QUOTED_IDENTIFIER ON
   9:  GO
  10:  IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tmtUsers]') AND type in (N'U'))
  11:  BEGIN
  12:  CREATE TABLE [dbo].[tmtUsers](
  13:      [UserId] [uniqueidentifier] NOT NULL,
  14:   CONSTRAINT [PK_tmtUsers] PRIMARY KEY CLUSTERED 
  15:  (
  16:      [UserId] ASC
  17:  )WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
  18:  ) ON [PRIMARY]
  19:  END
  20:  GO
 

tsrUsers

 
   1:  /****** Object:  Table [dbo].[tsrUsers]    Script Date: 07/06/2008 01:50:30 ******/
   2:  IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tsrUsers]') AND type in (N'U'))
   3:  DROP TABLE [dbo].[tsrUsers]
   4:  GO
   5:  /****** Object:  Table [dbo].[tsrUsers]    Script Date: 07/06/2008 01:50:31 ******/
   6:  SET ANSI_NULLS ON
   7:  GO
   8:  SET QUOTED_IDENTIFIER ON
   9:  GO
  10:  IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tsrUsers]') AND type in (N'U'))
  11:  BEGIN
  12:  CREATE TABLE [dbo].[tsrUsers](
  13:      [UserId] [uniqueidentifier] NOT NULL,
  14:   CONSTRAINT [PK_tsrUsers] PRIMARY KEY CLUSTERED 
  15:  (
  16:      [UserId] ASC
  17:  )WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
  18:  ) ON [PRIMARY]
  19:  END
  20:  GO


After creating the tables I went ahead and created a view that would link the UserId do the Grand Central Database and a respective stored procedure too.  I created these by simply dragging the tables onto the designer for creating the view from each of the respective databases. (Click to see the larger image)

The SQL for the views is below.  The TSR and TMT Databases both use basically the same exact SQL.

tmtUserListing

   1:  SELECT     dbo.tmtUsers.UserId, GrandCentral.dbo.aspnet_Users.UserName
   2:  FROM         dbo.tmtUsers LEFT OUTER JOIN
   3:                        GrandCentral.dbo.aspnet_Users ON dbo.tmtUsers.UserId = GrandCentral.dbo.aspnet_Users.UserId

tsrUserListing

   1:  SELECT     dbo.tsrUsers.UserId, GrandCentral.dbo.aspnet_Users.UserName, GrandCentral.dbo.aspnet_Users.LoweredUserName, GrandCentral.dbo.aspnet_Users.MobileAlias, 
   2:                        GrandCentral.dbo.aspnet_Users.IsAnonymous, GrandCentral.dbo.aspnet_Users.LastActivityDate
   3:  FROM         dbo.tsrUsers INNER JOIN
   4:                        GrandCentral.dbo.aspnet_Users ON dbo.tsrUsers.UserId = GrandCentral.dbo.aspnet_Users.UserId
 

and last but not least the two stored procedures.

tmtUserListingSelect

 
   1:  /****** Object:  StoredProcedure [dbo].[tmtUserListingSelect]    Script Date: 07/06/2008 01:36:33 ******/
   2:  IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tmtUserListingSelect]') AND type in (N'P', N'PC'))
   3:  DROP PROCEDURE [dbo].[tmtUserListingSelect]
   4:  GO
   5:  /****** Object:  StoredProcedure [dbo].[tmtUserListingSelect]    Script Date: 07/06/2008 01:36:33 ******/
   6:  SET ANSI_NULLS ON
   7:  GO
   8:  SET QUOTED_IDENTIFIER ON
   9:  GO
  10:  IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tmtUserListingSelect]') AND type in (N'P', N'PC'))
  11:  BEGIN
  12:  EXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE dbo.tmtUserListingSelect
  13:      
  14:  AS
  15:      SELECT     dbo.tmtUsers.UserId, GrandCentral.dbo.aspnet_Users.UserName
  16:  FROM         dbo.tmtUsers LEFT OUTER JOIN
  17:                        GrandCentral.dbo.aspnet_Users ON dbo.tmtUsers.UserId = GrandCentral.dbo.aspnet_Users.UserId
  18:                        
  19:      RETURN
  20:  ' 
  21:  END
  22:  GO

tsrUserListingSelect

 
   1:  /****** Object:  StoredProcedure [dbo].[tsrUserListingSelect]    Script Date: 07/06/2008 01:50:38 ******/
   2:  IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tsrUserListingSelect]') AND type in (N'P', N'PC'))
   3:  DROP PROCEDURE [dbo].[tsrUserListingSelect]
   4:  GO
   5:  /****** Object:  StoredProcedure [dbo].[tsrUserListingSelect]    Script Date: 07/06/2008 01:50:38 ******/
   6:  SET ANSI_NULLS ON
   7:  GO
   8:  SET QUOTED_IDENTIFIER ON
   9:  GO
  10:  IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tsrUserListingSelect]') AND type in (N'P', N'PC'))
  11:  BEGIN
  12:  EXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE dbo.tsrUserListingSelect
  13:      
  14:  AS
  15:  SELECT     dbo.tsrUsers.UserId, GrandCentral.dbo.aspnet_Users.UserName, GrandCentral.dbo.aspnet_Users.LoweredUserName, GrandCentral.dbo.aspnet_Users.MobileAlias, 
  16:                        GrandCentral.dbo.aspnet_Users.IsAnonymous, GrandCentral.dbo.aspnet_Users.LastActivityDate
  17:  FROM         dbo.tsrUsers INNER JOIN
  18:                        GrandCentral.dbo.aspnet_Users ON dbo.tsrUsers.UserId = GrandCentral.dbo.aspnet_Users.UserId
  19:      RETURN
  20:  ' 
  21:  END
  22:  GO
 

Now your server explorer should look like the image below.  (Click to see the larger image)

My database projects appear as below (all checked in). (Click to see the larger image)

Next we're going to setup the Data Access Layer (DAL).  Yes, this is somewhat crude, but really, we're only trying to get the basic objects and setup the business entities.  I've used SQL to LINQ for the DAL.  I dragged the three database objects from each "component" database over to the respective *.dbml files.

After that add the testing files to the various mbUnit test projects that have been created.  I create one for each of the objects that will be tested from the database, mainly based on the idea that they will generate entities or objects of some type, and this will keep them fairly organized.  A little bit more about this in part 2.

I'll have the next part up soon.  Until then this will get one setup for the initial tests and core data access layer.

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList