Testing SharePoint Workflows using TypeMock Isolator (Part 3)

Updated 12 June 2009 – I have been having problems using this technique of Typemock with Sharepoint Workflows, the workflows keep unexpectedly idling as opposed to activating. If you suffer similar problem please check for later posts as to any solutions I find. 

Now I can test a basic workflow it soon becomes obvious that you could end up with many tests for a single workflow, as a workflow can have any number of criteria that could cause branching to occur. Maybe a sensible way to write the tests is using Fit/Fitness to provide the test cases in tabular form?

So to this end I have added a bit more code to my Typemock/Sharepoint test project (after installing the Fit libraries as detailed in my previous posts). I now have a single test that loads a set of test criteria from an HTML file (my previous posts discuss why I am using HTML files as opposed to the Fit Wiki).

   1: [TestMethod]

   2:      public void WorkFlow1SwitchOnTitle_DataViaFitnesse_Success()

   3:      {

   4:          fit.Runner.FolderRunner runner = new fit.Runner.FolderRunner(new fit.Runner.ConsoleReporter());

   5:          var errorCount = runner.Run(new string[] {

   6:                  "-i",@"WorkflowTestCases.htm", // the htm file that holds the test

   7:                  "-a",@"TestProject.dll",  //we have the fit facade in this assembly

   8:                  "-o",@"results"}); // the directory the results are dumped into as HTML

   9:          // fit can fail silently giving no failures as no test are run, so check for exceptions

  10:          Assert.AreEqual(false, Regex.IsMatch(runner.Results, "^0.+?0.+?0.+?0.+?$"), "No tests appear to have been run");

  11:          // look for expected errors

  12:          Assert.AreEqual(0, errorCount, runner.Results);


  14:      }

I then have an HTML file that contains the test cases (remember to make sure that this file is deployed to the output directory)

Workflow Fit Tests
Upload Document With Title Document Approved?
ABC True
XYZ False
abc True


   1: <HTML><HEAD>

   2:     <body>

   3: <table border="1" cellspacing="0">

   4: <tr><td>import</td>

   5: </tr>

   6: <tr><td>TestProject</td>

   7: </tr>

   8: </table>


  10: <table border="1" cellspacing="0">

  11: <tr><td colspan="2">Workflow Fit Tests</td>

  12: </tr>

  13: <tr><td>Upload Document With Title </td>

  14: <td>Document Approved?</td>

  15: </tr>

  16: <tr><td>ABC</td>

  17: <td>True</td>

  18: </tr>

  19: <tr><td>XYZ</td>

  20: <td>False</td>

  21: </tr>

  22: <tr><td>abc</td>

  23: <td>True</td>

  24: </tr>

  25: </table>


  27:     </body>

  28: </html>


Finally we need to create the facade class that wrapper the workflow function for Fit to call. In this sample I just popped the class in the test project for simplicity. Notice it is this facade class that contains all the Typemock bits, also that I make use of the helper class I created in my previous post to actually run the workflow.

   1: using System;

   2: using TypeMock.ArrangeActAssert;

   3: using Microsoft.SharePoint.Workflow;


   5: namespace TestProject

   6: {

   7:     public class WorkflowFitTests : fit.ColumnFixture

   8:     {

   9:         public string UploadDocumentWithTitle;


  11:         public bool DocumentApproved()

  12:         {


  14:             var fakeProperties = Isolate.Fake.Instance<SPWorkflowActivationProperties>();

  15:             var fakeItem = fakeProperties.Item;

  16:             Isolate.WhenCalled(() => fakeItem.Title).WillReturn(this.UploadDocumentWithTitle);


  18:             // Act

  19:             TypemockWorkflowTests.WorkflowRunner(typeof(SharePointWorkflow.Workflow1), fakeProperties);


  21:             // Assert, if a document is approved must call the following two line

  22:             try

  23:             {

  24:                 Isolate.Verify.WasCalledWithExactArguments(() => fakeItem.Update());

  25:                 Isolate.Verify.WasCalledWithExactArguments(() => fakeItem["Approved"] = "True");

  26:                 return true; // we called all the updates expected

  27:             }

  28:             catch (TypeMock.VerifyException)

  29:             {

  30:                 // it did not call something expected, check if it was just the not approved path

  31:                 Isolate.Verify.WasNotCalled(() => fakeItem.Update());

  32:                 return false;

  33:             }


  35:         }

  36:     }

  37: }

I am currently working on a sample of this testing technique, that does a bit more than a simple branch on if test, I will post a set of sample code when I am done.