EvilDevilCuckoo, Evil Devil Cuckoo, William Ryan, W.G. Ryan, Bill Ryan, Kim Ryan, Search Engine Optimization, Data Mining

 16 Apr 2014 @ 11:27 PM 

Unit Testing MSCRM 2011 – Part I of V

Unit Testing MSCRM 2011 is really no different than testing any other .NET application with the possible exception of Plugins and Workflows. However many shops completely overlook automated unit testing and that is very likely one contributing factor to why so many MSCRM projects fail or are much harder than they need to be.

Introduction:

One thing that has always bothered me about Microsoft Dynamics CRM development is how organizationally, it’s not treated like ‘real’ development.   What does that mean exactly? Well, it depends.  I’ve been a consultant at several companies. From very small ones (1-2 developers) to large ones (multiple teams with over 30+ developers and every formal role that goes along with it).  I can think of only 3 that had an actual API or Framework of truly reusable CRM code that projects were put together with (this isn’t the same thing as saying they didn’t reuse code just so I’m being clear).  I can think of only two that had automated unit testing. I can think of only 2 that had automated builds.  You get the idea hopefully.  You use C# or Visual Basic .NET for the most part to build CRM applications. You use ASP.NET, Silverlight, Windows Communication Foundation, Workflow Foundation to build out CRM Applications. You do most if not all of your development inside of Visual Studio .NET.  Yet in many cases, you could count more differences than similarities with respect to CRM projects and other ones.  So let this be an opening salvo in trying to enlist others to build CRM projects the same way they build other .NET Projects. Unit Testing MSCRM 2011 happens all too infrequently in most places if it happens at all, and as easy as it is to do, few things can aid your project’s quality more than Unit Testing MSCRM 2011.

MSTEST

There are several good tools to implement automated Unit Testing MSCRM 2011 with. Those include NUnit, MBUnit, MSTest , Telerik Test Studio and others. If you’d like to debate the merits of one framework over the other, there are plenty of places on the net that you’ll find many kindred spirits.  You won’t find one here.  What matters is that you automate your unit testing, any of the popular tools should suffice.  If you haven’t started unit testing, aren’t familiar with it or need to understand why it matters, you’d do well to do some background searching on the subject first. As far as I’m concerned, the debate as to whether or not you should unit test and how comprehensively you should do it was finished years ago.  You should definitely write automated unit tests. You should test early and often.  And you should test as much of your code base as you can.

[TestClass]

Visual Studio lets you create separate Unit Test Projects that serve as convenient containers to hold your tests. If you use another framework, the same principles apply.  Assuming that you’re using Visual Studio 2013 Professional (or an edition with Testing enabled), you’ll see a distinct Test Menu (Figure 1-1) that will allow you to interact with Test Explorer (Figure 1-2) among other things:

Figure 1-1Visual Studio 2013 Test Menu

MSTest Test Menu Options Visual Studio 2013

Test Menu Options in Visual Studio 2013

Figure 1-1Visual Studio 2013 Test Explorer

Microsoft Visual Studio 2013 Test Explorer

Visual Studio 2013 Test Explorer

Microsoft Visual Studio 2013 Test Explorer

Visual Studio 2013 Test Explorer

 

To start with, you should give your classes a coherently named Namespace.  YourCompanyName.ProjectName.Tests works as a starting point.  From there, you have 3 choices of items you can add to your Test Project:

  1. Basic Unit Test (An empty basic Unit Test Declaration)
  2. Ordered Test (Use an ordered test to execute a set of existing tests in an order you specify)
  3. Unit Test (An empty Unit Test class declaration)

The summaries at the end of each item pretty aptly describe what they do.  The important takeaway is that each set of test cases you want to run should be contained in a class definition that’s decorated with the [TestClass] attribute.

AssemblyInitialize & AssemblyCleanup

Lacking a better metaphor, you can think of AssemblyInitialize & AssemblyCleanup as outer layers of an onion.  MSDN describes AssemblyInitialize in the following way:

Identifies a method that contains code to be used before all tests in the assembly have run and to allocate resources obtained by the assembly.

AssemblyCleanup is the inverse counterpart, running at the end of everything to serve as the final cleanup agent.

Do you need these? Maybe, maybe not.  Generally speaking, a good unit test will allow itself to run in whatever environment the developers want it to.  To do that, it must generally be configurable.  Then it should create all the data it needs.  The tests should be run on this data validating the code along the way. Finally, the data that was created for the test should be removed so that the system is in the same state it was when the testing began.

At this point I’ll take a slight digression. I’ve heard (and participated in) many arguments around this subject. Many will argue that you can create effectively disposable CRM online instances so that cleaning up the data at the end isn’t really necessary. Personally, I don’t see much validity in this unless you’re coming from the “I don’t do anything more than the minimum I have to” perspective.  Others will argue you can use Virtual Machine images, load the data once there, save snapshots etc etc, thereby negating the need for adding data and cleaning it up. I think it’s a lame argument b/c it seems like it requires more resources and makes things less atomic, but devotees insist they can script things and do it in a way that’s faster than anything that can be done with setup and teardown.  Whatever.  The main point is that you want to test your code logic – you don’t want to get false positives or negatives b/c of a data issue. If you have a way that’s repeatable, can be run in multiple environments and doesn’t open itself up to data issues, go with my blessing.  Just keep in mind that if done correctly, your unit tests can (and should) validate that any given version of code will run on a given environment. If you do a promotion or deploy a new solution/web site /whatever, unit tests can be run against that environment to verify everything works as advertised.  This may or may not be advisable on a production system but it certainly is something you want to do everywhere else.  Creating the data, testing it and deleting it is one sure way to accomplish this goal.

Anyway, if you want to set up data that spans classes, AssemblyInitialize and AssemblyCleanup are the places to facilitate that.

 

ClassInitialize & ClassCleanup

ClassInitialize and ClassCleanup are the next layer of the onion. ClassInitalize runs when an instance of the class is created, and ClassCleanup is run after all the tests in the class have been run. The only thing noteworthy about these are that they are static, and ClassInitialize takes in an instance of the TestContext class.  The TestContext class is a container that lets you store things that you can reference throughout the tests.

The signature for Class initialize is shown below:

private static TestContext currentTestContext;

///<summary>

///Gets or sets the CurrentTestContext property.

///</summary>

publicstaticTestContext CurrentTestContext

{

      [DebuggerStepThrough()]

      get

{

        return currentTestContext;

}

      [DebuggerStepThrough()]

      set

{

          currentTestContext = value;

}

}

 

[ClassInitialize()]

publicstaticvoid ClassInitialize(TestContext context)

{}

Anyway, this is a great place to load data.  For instance, you may have data corresponding to each entity you want to create stored in an Excel sheet.    Here is a working example of code I used in production to load a list of Dealers from an Excel sheet.  The location is stored in a settings file so hopefully you can deduce that on your own.  Also keep  in mind that with excel, each Sheet name corresponds to a Table name, it just uses a Dollar Sign $ character at the end of it:
String ConnectionString = @Settings.Default.ExcelFileLocation;

DataTable dt = newDataTable();

OleDbConnection conn = newOleDbConnection(ConnectionString);

String SQL = String.Format(CultureInfo.CurrentCulture, “SELECT * FROM [{0}$]”, “Dealer”);

OleDbDataAdapter adapter = newOleDbDataAdapter(SQL, conn);

adapter.Fill(dt);

Afterward, I call a method called HydrateDealers where I just pass in the DataTable, loop through the rows and then create the corresponding entities.  I also create a collection of Guids corresponding to the newly created entity id values.  This is so that in the ClassCleanup method, I can just loop through the collection, using the entity type (in this case, dev_dealer) and the id and calling the OrganizationServiceInstance Delete method.  Exception handling only writes to the Console for this example, in practice I log it using the EnterpriseLibrary and using the TestResults feature, but the article is already getting too hard to read.

So using the ClassCleanup counterpart, this method runs for each of the collections that I populated earlier. Using the stored Guids (which I get from the OrganizationService.Create ) I can loop through each collection and delete anything I created. Done correctly, I leave the system in the exact same shape I got it with respect to data.  This means no “Test Accounts” or any garbage of that sort in the system:

[ClassCleanup]

public static void CrmCleanup()

{

foreach (Guid dealerId inFinancingUnitTest.CurrentDealersList)

{

try{

ServiceInstance.Delete(“dev_dealer”, dealerId);

}

catch (Exception ex){

Console.WriteLine(ex.ToString());

}

}

TestInitialize & TestCleanup

These run at the beginning and end of each test and let you set things up and tear things down that are specific to the test.  The same principle applies here that applies to the AssemblyInitialize , AssemblyCleanup , ClassInitialize and  ClassCleanup attributes, they just let you apply them at a more granular level.  The Assembly attributes are the outermost layer of the onion, the Test attributes are the innermost ones.

Now, one last thing before closing this portion of the article.  It is often useful to have a reference to the OrganizationService.  My preference is to create a property of Type CrmConnection and one of type OrganizationService (if you don’t know how to do that, there are several examples throughout this blog).  This particular approach lends itself well to the so-called ‘late bound’ approach to CRM coding.  But the same principal can be applied using the early bound approach (using the OrganizationServiceClient) or the OrganizationServiceContext.  The main point is that you have something to hook onto to run and test your methods.

With that in mind, the next article will walk through creating several tests using the [TestMethod] attribute

Donate Dogecoins: DFxAsJEQenZvj8W8BcvMmMpZVp8DhFUr4a Whats This?

Technorati Tags: , , , , , , , ,

Share and Enjoy

  • Facebook
  • Twitter
  • Delicious
  • Digg
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS


 

Responses to this post » (3 Total)

 
  1. [HOOK NOSED SPAMMER] says:

    [CUCKOOBOT 3.6.9.9 detected questionable content. Message was NOT disenvoweled]
    ft 14

    Unit Test MSCRM 2011 | Random Musings from Bill Ryan

  2. CRM Blogger says:

    See my comments to the second article in this post. You put so much effort into the first two articles and you are the only person I know of who has covered this topic, it’s really disappointing to see it drop off. Without prodding I suspect that you’ll ‘be too busy’ to ever write Article 3, 4 & 5. Maybe you should get a co-blogger for such series. If not, either promise less or commit yourself to following through Bill. As someone who’s followed your writing for years, this is all too typical. You consistently throw out these tidbits covering things no one else has written about (or even thought about in some cases) and then fail to follow up. If nothing else, why not write the whole series first before posting anything, then set the post dates to future dates? Honestly, the frequency with which you do this really smacks of irresponsibility or immaturity.

  3. Dynamics Explorer says:

    I’ve been looking for some articles on unit testing MSCRM but never even thought about using data driven tests. Great posts. Please hurry up and write the rest of the series. And can you post the source code of the projects you used?

Tags
Comment Meta:
RSS Feed for comments

 Last 50 Posts
 Back
 Back
Change Theme...
  • Users » 10689
  • Posts/Pages » 123
  • Comments » 418
Change Theme...
  • VoidVoid « Default
  • LifeLife
  • EarthEarth
  • WindWind
  • WaterWater
  • FireFire
  • LightLight

Code Sample Reference



    No Child Pages.

Disclaimer



    No Child Pages.