How to create an Asynchronous Workflow Integration Test

In this example, we explain how to test the workflow "Update Account Value", which calculates the value of an account based on its related opportunities and send an email to the account's owner if that value is greater than 1 Million.

This workflow uses the custom workflow activity "TotalOpportunities", which has been detailed and tested in our previous sample Create a Custom Workflow Activity Integration Test. You should notice these tests cover different scopes. While that test is focused on the logic of that custom workflow activity, the current test is going to cover other aspects of a bigger picture part of the workflow "Update Account Value, such as the email that needs to be sent.

To create this test, just follow the next steps:
  • Right click on the folder WFActivities of the Integration Test project
  • Add the new item
  • Dynamics CRM => Select "WFActivity Integration Test Using Workflows" template

"Update Account Value" workflow:
xRMTestFramework_UpdateAccountValueWorkflow.jpg

"WFActivity Integration Test Using Workflows" template:
xRMTestFramework_AddWFActivityIntegrationTestUsingWorkflows.jpg

TestUpdateAccountValueWorkflow.cs test code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;
using Xrm.Framework.Test.Integration;
using Xrm.Solutions.FrameworkSample.Common.Entities;


namespace Xrm.Solutions.FrameworkSample.XrmIntegrationTests.WFActivities
{
    [TestClass]
    public class TestUpdateAccountValueWorkflow : WFActivityIntegrationTest
    {
        #region Properties

        protected override string AsyncOperationName
        {
            get
            {
                return "Update Account Value";
            }
        }

        #endregion

        #region Instance Variables

        private Account account;
        private List<Opportunity> accountOpportunities;

        #endregion

        #region Setup


        protected override Guid SetupPrimaryEntity()
        {
            CrmHelpers.SetConfigurationSetting(this.OrganizationService, "AutoNumberPrefix", "Test" + DateTime.Now);

            account = new Account();
            account.Name = "TestUpdateAccountValueWorkflow " + DateTime.Now;
            account.Id = this.OrganizationService.Create(account);

            Opportunity opportunity1 = new Opportunity();
            opportunity1.Name = "TestUpdateAccountValueWorkflow 1 " + DateTime.Now;
            opportunity1.ActualValue = new Money(800000);
            opportunity1.ParentAccountId = account.ToEntityReference();
            Opportunity opportunity2 = new Opportunity();
            opportunity2.Name = "TestUpdateAccountValueWorkflow 2 " + DateTime.Now;
            opportunity2.ActualValue = new Money(200000);
            opportunity2.ParentAccountId = account.ToEntityReference();

            opportunity1.Id = this.OrganizationService.Create(opportunity1);
            opportunity2.Id = this.OrganizationService.Create(opportunity2);

            accountOpportunities = new List<Opportunity>(2);
            accountOpportunities.Add(opportunity1);
            accountOpportunities.Add(opportunity2);

            return opportunity2.Id;
        }

        #endregion

        #region Test

        [TestMethod]
        public void RunTestUpdateAccountValueWorkflow()
        {
            base.Test();
        }

        #endregion

        #region Verify

        protected override void VerifyStatus()
        {
            Assert.AreEqual(Status, AsyncStatus.Pass);

            //Verify Account Value
            decimal expectedTotal = this.accountOpportunities.Sum(op => op.ActualValue.Value);
            decimal actualTotal = RetrieveActualAccountValue();
            Assert.AreEqual(expectedTotal, actualTotal);

            //Verify email has been sent since Account is worth more than One Million
            IQueryable<Email> emails = AccountEmails(this.account);
            Assert.IsNotNull(emails);
            Assert.IsTrue(emails.ToList().Count > 0);
            
        }

        private IQueryable<Email> AccountEmails(Account account)
        {
            using (XrmServiceContext xrmContext = new XrmServiceContext(this.OrganizationService))
            {
                var emails = from email in xrmContext.EmailSet
                           where email.RegardingObjectId.Id == account.Id
                           select email;
                return emails;
            }
        }

        private decimal RetrieveActualAccountValue()
        {
            decimal actualTotal = 0M;

            using (XrmServiceContext xrmContext = new XrmServiceContext(this.OrganizationService))
            {
                var opps = from opp in xrmContext.OpportunitySet
                           where opp.AccountId.Id == account.Id
                           select opp.ActualValue;

                foreach (Money actual in opps)
                {
                    actualTotal += actual.Value;
                }
            }

            return actualTotal;
        }

        #endregion

        #region Clean up

        protected override void CleanUp()
        {
            base.CleanUp();

            foreach (Opportunity opp in accountOpportunities)
                this.OrganizationService.Delete(opp.LogicalName, opp.Id);

            this.OrganizationService.Delete(account.LogicalName,account.Id);
            
        }

        #endregion
    }
}

This test follows the same structure as Create a Custom Workflow Activity Integration Test, but it verifies an email has been sent for the created account.

This test also has a very important code section to notice:
protected override string AsyncOperationName
{
     get
     {
           return "Update Account Value";
     }
}
Overwrite the property AsyncOperationName allows to specify the name of the workflow to be tested, which must fulfil the next requirements:
  • Workflow available to run as on-demand process
  • Disable Workflow Job Retention
Obviously, these settings are only required at the test environment where the tests are going to be run, but they should be updated in your production environment accordingly.

At this stage, you should wonder "How both tests have almost the same logic and structure, but one is testing a custom workflow activity using an Action and the other using an asynchronous Workflow?"

The answer is simple: xRM Test Framework base classes. Our base classes handle behind the scene the corresponding connections and trigger the right elements, leaving you to worry only about the important core of your test, which is mainly the Setup and Verify stages.

Last edited Jun 9, 2014 at 7:58 PM by rtebar, version 7

Comments

No comments yet.