Testing SharePoint Workflows using TypeMock Isolator (Part 3)

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);
  13:          
  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)



   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>
   9:     
  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>
  26:  
  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;
   4:  
   5: namespace TestProject
   6: {
   7:     public class WorkflowFitTests : fit.ColumnFixture
   8:     {
   9:         public string UploadDocumentWithTitle;
  10:  
  11:         public bool DocumentApproved()
  12:         {
  13:  
  14:             var fakeProperties = Isolate.Fake.Instance<SPWorkflowActivationProperties>();
  15:             var fakeItem = fakeProperties.Item;
  16:             Isolate.WhenCalled(() => fakeItem.Title).WillReturn(this.UploadDocumentWithTitle);
  17:  
  18:             // Act
  19:             TypemockWorkflowTests.WorkflowRunner(typeof(SharePointWorkflow.Workflow1), fakeProperties);
  20:  
  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:             }
  34:  
  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.