BDD for Dynamics 365 CE – Part 4 – Unit Testing

In the previous post I showed you how you can apply BDD for system testing. Ideally you want to be starting here actually.

System tests can take longer to write than unit tests. Unit test can be useful to test your plug-ins, custom workflow activities, JavaScript and other custom code you write. They are the fastest to run and thus give you instant feedback.

What tool we will use?

Again we will be using SpecFlow to define requirements and drive test automation. We will also be using FakeXrmEasy framework. This is an excellent framework that provides with an in-memory CRM database that your tests can run against.

How do we fine requirements?

I will be using the same scenario and language that I used in the system testing.

Feature: Introductory phone call

In order to provide excellent customer service
As a customer service
I want to arrange a follow up phone call with new customers

Scenario: Follow Up Phonecall on Account Creation

Given I login to CRM
When I create a new account
Then a phone call record should be created
And due date should be in 5 days

Can we apply TDD to unit testing too?

Absolutely. Let’s assume we will implement this logic in a plug-in. Before we do that let’s created the automated test first and make it fail.

How do we create the automated tests?

By now you should be familiar with SpecFlow from the previous posts. Let’s take a look at the implementation of the scenario in the content of unit testing.

Given I login to CRM
When I create a new account

In unit testing we don’t need to connect to CRM. So instead I will be creating a fake CRM proxy using the FakeXrmEasy Framework.

Given I have decided to implement the logic using a plug-in. All I have to do is create a place holder plug-in ‘AccountPostCreate’. Then I can use the framework to execute the plug-in using a target account.

        [Given(@"I login to CRM")]
        public void GivenILoginToCRM()
        {
            ctx = new XrmFakedContext();
        }

        [When(@"I create a new account")]
        public void WhenICreateANewAccount()
        {
            Entity account = new Entity("account");
            account.Attributes["name"] = "Wael";
            account["telephone1"] = "123456789";

            ctx.ExecutePluginWithTarget(account);
        }

How let’s look at the verification lines.

Then a phone call record should be created
And due date should be in 5 days

After the plug-in executes I am expecting a new phone call record associated with the account. So in this case I will query the fake context for the phone calls and then verify that the phone call has the expected due date.

        [Then(@"a phone call record should be created")]
        public void ThenAPhoneCallRecordShouldBeCreated()
        {
            var phonecalls = ctx.CreateQuery("phonecall").ToList();
            Assert.AreEqual(1, phonecalls.Count);
            phonecall = phonecalls[0];
        }

        [Then(@"due date should be in (.*) days")]
        public void ThenDueDateShouldBeInDays(int days)
        {
            DateTime dueDate = (DateTime)phonecall["scheduledend"];
            DateTime createdOn = (DateTime)phonecall["createdon"];
            Assert.AreEqual(dueDate.Date, createdOn.Date.AddDays(days));
        }

What happens if the test runs now?

Given I have not implemented anything it should fail. But now I should exactly what I need to do in the plug-in to make this test pass.

After I add the below code, the test should pass.

    public class AccountPostCreate : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            // Obtain the execution context from the service provider.
            IPluginExecutionContext context = (IPluginExecutionContext)
                serviceProvider.GetService(typeof(IPluginExecutionContext));

            // Obtain the organization service reference.
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

            if (context.InputParameters.Contains("Target") &&
                context.InputParameters["Target"] is Entity)
            {
                var target = context.InputParameters["Target"] as Entity;

                Entity phonecall = new Entity("phonecall");
                phonecall["regardingobjectid"] = target.ToEntityReference();
                phonecall["phonenumber"] = target["telephone1"];
                phonecall["scheduledend"] = DateTime.Now.AddDays(5);
                phonecall["subject"] = "Introductory phonecall";

                service.Create(phonecall);
            }
        }
    }

Now you you can deploy the plug-in to CRM and run the system test that we created in the previous post which should pass now too.

 

You can find all the code from this and all the previous posts on GitHub.

What have we learned?

  1. You can also use BDD to drive unit tests for CRM customisations that are implemented in code (i.e. plug-ins, custom activities, JavaScript, custom classes)
  2. Even though we have been writing a test for a plug-in, if you look at the specification and scenario, it will also make sense to the business user who may not have the technical knowledge about the implementation
  3. The automated tests will continue to ensure system will meet this requirement as the system evolves
  4. Looking at the test and scenario any other team member will understand why the plug-in is there and what purpose it serves

Conclusion

In the last few post I showed you different ways in which you can apply BDD to your Dynamics 365 CE project to improve understanding, software quality and DevOps practices. Although BDD may not be for every team and everything, it can certainly add value for some teams and scenarios.

Hope you founds these useful. Let me know what you think.

Advertisements

BDD for Dynamics 365 CE – Part 3 – System Testing

In the previous post I showed you how you can use BDD to define and write acceptance tests. Acceptance tests at UI layer are great for smoke testing and regression packs, but they do take long to run and it may be difficult to test certain capabilities like complex logic and integrations at UI layer.

In this post I will show you how you can apply BDD to write system and integration tests for Dynamics 365 CE.

What are system and integration tests?

These are the tests that work against the components below the UI layer. In the context of CRM this can mean running tests against the CRM Sdk Services or any of your custom components that have a dependency on CRM.

What tools do you need?

We will again be using SpecFlow to define the scenarios and drive test automation. You will also need to reference the CRM Sdk Libraries.

How do you define requirements?

Using the same way as we did with acceptance testing. Let’s take a look again at the same scenario. Note this scenario is a bit simpler than the one used for UI testing as it doesn’t contain the UI flow but rather focuses on functionality.

Feature: Introductory phone call

In order to provide excellent customer service
As a customer service
I want to arrange a follow up phone call with new customers

Scenario: Follow Up Phonecall on Account Creation

Given I login to CRM
When I create a new account
Then a phone call record should be created
And due date should be in 5 days

What is TDD?

If you are a developer and you were to meet the above requirement, you could just jump straight into implementation. You could create a process or plug-in to do this.

In Test-driven development (TDD) you write the tests first. The test will fail. Then you can implement the functionality to make the test pass. Let’s do that next.

How do I create the automated test?

Again SpecFlow can help with this. We need to link each of the scenario lines into implementation. Let’s take a look at some examples.

Given I login to CRM

Essentially the login process will end up being instantiating an instance of the CRM Proxy.

        [Given(@"I login to CRM")]
        public void GivenILoginToCRM()
        {
            string url = Environment.GetEnvironmentVariable("CrmUrl", EnvironmentVariableTarget.User);
            string user = Environment.GetEnvironmentVariable("CrmUsername", EnvironmentVariableTarget.User);
            string pass = Environment.GetEnvironmentVariable("CrmPassword", EnvironmentVariableTarget.User);

            string con = $"AuthType=Office365;Username={user};Password={pass};Url={url}";

            service = new CrmServiceClient(con);
        }

Let’s take a look at the second line. This scenario is focusing on phone call creation but you could also add more details around the account and phone call fields or cover it as part of other scenarios.

When I create a new account

For this one you will just call the CRM service and create a new account.

        [When(@"I create a new account")]
        public void WhenICreateANewAccount()
        {
            account = new Entity("account");
            account.Attributes["name"] = new RandomGenerator().GetString(8);
            account["telephone1"] = "123456789";
            account.Id = service.Create(account);
        }

And finally comes the verification lines which are very important.

Then a phone call record should be created
And due date should be in 5 days

In the below methods I am just calling the CRM Service to verify that a phone call has been created. Notice the second line. I have created a parameter for the due date. This allows someone to easily change the days later without impacting the implementation of the test.

        [Then(@"a phone call record should be created")]
        public void ThenAPhoneCallRecordShouldBeCreated()
        {
            QueryByAttribute query = new QueryByAttribute("phonecall");
            query.Attributes.Add("regardingobjectid");
            query.Values.Add(account.Id);
            query.ColumnSet = new ColumnSet("scheduledend", "createdon", "activityid");
            EntityCollection results = service.RetrieveMultiple(query);
            Assert.AreEqual(results.TotalRecordCount, 1);
            phonecall = results[0];
        }

        [Then(@"due date should be in (.*) days")]
        public void ThenDueDateShouldBeInDays(int days)
        {
            DateTime dueDate = (DateTime)phonecall["scheduledend"];
            DateTime createdOn = (DateTime)phonecall["createdon"];
            Assert.AreEqual(dueDate.Date, createdOn.Date.AddDays(days));
        }

What happens if you run the test now?

Given I haven’t done anything in CRM yet, the test will fail. Now I need to implement functionality to make the test pass or in other words to make sure that system meets user requirements.

You can see the full implementation of these steps on GitHub.

What have we learned?

As your system evolves you may have lots of processes, plug-ins and logic in different places which can be difficult to keep track on how everything hangs together and what is the current expected behaviour of the system.

  1. BDD can be used for CRM system testing too
  2. BDD specification is live documentation about your system behavior
  3. You can use BDD to create automated tests to ensure your system meets and continues to meet user requirements as it evolves.

Even if you don’t use BDD to communicate with business users, you can still use it within your team. That is documenting expectation between BAs/developers or architects/developers and testers.

What is next?

In the next post I will show you how you can apply BDD to unit testing too for the same scenario.

 

BDD for Dynamics 365 CE – Part 2 – Acceptance Testing

Given BDD is user-centered approach to development, it makes sense to start showing you how you can use BDD in the context of user acceptance testing (UAT) . If you are new to BDD, you can read my previous intro post.

What is user acceptance testing?

Essentially any testing you do will eventually be contributing towards making sure that the system is accepted by users in the sense that it meets user requirements. However in most cases the users will be interacting with Dynamics 365 CE UI and they expect the UI to provide the features they need. So in this post I will focus on how we can use BDD to ensure the application will deliver the expected user experience.

What tool do you need?

I will be using the popular SpecFlow framework. This will allow you to define our requirements and drive automated testing.

I will also be using EasyRepro framework. This will allow you to interact with the CRM UI as part of automated testing.

If you are new to EasyRepro and UI Automation, you can read my previous posts on this.

How do you document the requirements?

In SpecFlow you document the requirements in Gherkin language using feature files that contain scenarios. Each feature can have multiple scenarios. Think of these specifications are your acceptance criteria for your user stories.

Most likely you will first have high level discussions with your users around what they need, as you get to details and have grooming sessions with your team, you will arrive at the BDD requirement specification. This is the agreed scenario that the system is expected to provide.


Feature: Introductory phone call

In order to provide excellent customer service
As a customer service
I want to arrange a follow up phone call with new customers

Scenario: Follow Up Phonecall on Account Creation

Given I login to CRM
When I navigate to Sales and select Accounts
Then I click on New command
And I set value of name to RandomString of 8
And I set value of telephone1 to '123456789'
And I set value of websiteurl to 'http://dynamics.microsoft.com'
Then I click on Save command
When I go to social pane and select Activities
Then Activity timeline count should be equal to 1

How do you ensure requirements are met?

Firstly as you can see from the above, the specification can be easily understood by the business user and it is specific enough for developer and testers to implement and verify. The chance for different team members to have a different understanding is very low.

Secondly you can take this to the next level by linking your specification to automated tests.

How do you link scenarios to tests?

Luckily SpecFlow does most of the hard work for you. Essentially every statement in the scenario has an equivalent piece of code that executes as the test automation framework runs through the scenario. Let’s take a look at a few examples.

Given I login to CRM

The first line in the scenario will basically translate into the below method that will open a new instance of the browser pointing to CRM.

        [Given(@"I login to CRM")]
        public void GivenILoginToCRM()
        {
            string url = Environment.GetEnvironmentVariable("CrmUrl", EnvironmentVariableTarget.User);
            string user = Environment.GetEnvironmentVariable("CrmUsername", EnvironmentVariableTarget.User);
            string pass = Environment.GetEnvironmentVariable("CrmPassword", EnvironmentVariableTarget.User);

            xrmBrowser = new XrmBrowser(options);
            xrmBrowser.LoginPage.Login(new Uri(url), user.ToSecureString(), pass.ToSecureString());
            xrmBrowser.GuidedHelp.CloseGuidedHelp();

            xrmBrowser.ThinkTime(500);
        }

Let’s take a look at another scenario line.

Then I click on New command

In the second case we have added the parameter ‘command’ to the method. When this scenario line executes, it will pass ‘New’ to the method.

This is great because you only need to write the code for the click command once and you can re-use this in many scenarios. Eventually you will have handlers for most of the user actions. So creating automated tests will not take very long.

        [Then(@"I click on (.*) command")]
        public void WhenIClickCommand(string command)
        {
            xrmBrowser.CommandBar.ClickCommand(command);
            xrmBrowser.ThinkTime(1000);
        }

You can take a look at the full implementation of this scenario on GitHub.

What have we observed?

  1. We can use Gherkin/SpecFlow to clearly define requirements using specification that can understand by all team members
  2. We can use SpecFlow/EasyRepro to link specification to automated tests
  3. Once grammar and implementation are created for a specific action, this can be re-used in other scenarios
  4. Using BDD we can ensure the system will meet the user requirements

Note this particular scenario that I can described can be useful to define smoke or regression packs that can be run as part of automated build/deployment to ensure your high level acceptance tests are regularly tested and working.

Whats next?

In the next post I will show you how you can apply BDD to other types of tests.

BDD for Dynamics 365 CE – Part 1 – Intro

Behaviour Driven Development (BDD) and Test Driven Development (TDD) are not terms you often hear when working on Dynamics 365 CE projects. However with the rising interest in adopting DevOps, availability of tools and increasing number of large scale deployments, will these practices become more widely used? I will try to answer this question in this post…

What is BDD?

Essentially BDD is framework that can be applied to software projects to ensure that the delivered product will meet the stakeholders expectations and desired outcome is achieved.

Why use BDD?

Many projects fail because requirements are not clearly specified, also the requirements can get interpreted differently by stakeholders, analysts, developers and testers. BDD ensures requirements are clearly defined and understood by all parties.

Quality issues can arise if implementation and testing is not inline with requirements especially as the system evolves, BDD ensures implementation remains inline with requirements by keeping a constant link between evolving requirements and tests.

How BDD Works?

In BDD you take a user-centered approach to define the behaviour of the system using scenarios and examples. This is defined using a ubiquitous language that can be understood by all parties involved.

Once scenarios and examples are defined and agreed using language specification, the specification is used as a basis for automated testing to ensure that system meets the desired outcome.

What is Ubiquitous language?

It is a language that can be used to describe the behaviour of the system using scenarios and examples. This is the contract between all parties (business, developers, testers) that everyone understands and agrees to.

Gherkin is the most widely adopted language in BDD and it follows Given-When-Then format.

How to describe behaviour using Gherkin?

Below is a simple example of a given scenario. I won’t explain this any further because the whole point of using specification is that things are clearly understood by all parties.

Feature: Introductory phone call

In order to provide excellent customer service
As a customer service
I want to arrange a follow up phone call with new customers

Scenario: New account creation

Given I login to CRM
When I create a new account
Then a phone call record should be created
And due date should be in 5 days

What is the cost?

The team needs to spend some time to get familiar with BDD and agree on using a language like Gherkin. The next step would be to use a framework that can translate these to automated tests that can be written and maintained by developers.

Is BDD Suitable for Dynamics 365 CE projects?

Dynamics 365 CE is a very rich SaaS offering. In fact you can meet many of the user requirements through configuration  without having to write any code. That might mean that you may not even have developers on your team to write the automated tests. BDD may not be suitable for all projects.

When can BDD be useful for Dynamics 365 CE projects?

  1. You want to use automated testing to increase quality and reduce regression cycles
  2. You want to adopt DevOps methodologies to delivery regular business value
  3. You want tractability between requirements, implementation and testing
  4. You want to ensure requirements are clearly defined and understood by all parties

Note even if you don’t go down the route of automated testing, there may be still some value you can gain by using BDD specification to define requirements.

Can I see some examples?

BDD may not be suitable for everything, in the following posts I go through several scenario where BDD can add value and show you how you can implement this in practice. You can then decide whether it is something that can add value and help you with your Dynamics 365 CE projects.

Let me know what you think…

Dynamics 365 CE TLS Connectivity Issue from .NET and PowerShell

If you have been running recently into some strange unexplained connectivity issues to Dynamics 365 CE Online, then the chances are this might be due to TLS incompatibility between Dynamics and your client code.

What is the issue?

Microsoft has started to disable TLS 1.0 and TLS 1.1 support for Dynamics 365 online instances. That means only TLS 1.2 will be supported. Obviously this is for good reasons to improve security.

What is impacted?

Any of your clients or PowerShell Modules/Scripts that relies on the CRM SDK. This includes CRM development tools, CRM Package Deployment PowerShell Tools, Custom clients/portal/services and others.

Suggested Fixes?

You can find out more information about this change and potential fixes in this article. To cut a long story short, you either have to update your .NET client to 4.6.2 or provide implement a machine wide registry key to enforce highest security protocol (TLS 1.2).

How to see your current settings from code?

From .NET

Console.WriteLine(ServicePointManager.SecurityProtocol);

From PowerShell

$currentProtocol = [System.Net.ServicePointManager]::SecurityProtocol
Write-Verbose "Current Security Protocol: $currentProtocol"

This gets more complicated…

I noticed that even if you have PowerShell Cmdlets compiled in .NET 4.6.2, PowerShell will still sometimes run in its own run-time depending on the machine configuration.

So for example on my Windows 10 Machine with PS 5.1 by default I could only see SSL3 and TLS available. You will probably see the same on a .NET Client compiled using .NET 4.5.2 or earlier.

Alternative Solution…

So if you want to keep your .NET version or if you are facing the issues when running PowerShell you can try the solutions below.

If you are connecting to a known CRM instance/version. Then you force the connection to use TLS 1.2 using the code below.

From .NET

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

From PowerShell

[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;

However if you are building something that may need to connect using previous security protocol, for example a generic PowerShell Module that can be used for Online and On-premises. You probably want to keep your options open. The below code will check your current settings and add TLS 1.1 and TLS 1.2 support if not already configured.

From .NET

            WriteVerbose(string.Format("Current Security Protocol: {0}", ServicePointManager.SecurityProtocol));

            if (!ServicePointManager.SecurityProtocol.HasFlag(SecurityProtocolType.Tls11))
            {
                ServicePointManager.SecurityProtocol = ServicePointManager.SecurityProtocol ^ SecurityProtocolType.Tls11;
            }
            if (!ServicePointManager.SecurityProtocol.HasFlag(SecurityProtocolType.Tls12))
            {
                ServicePointManager.SecurityProtocol = ServicePointManager.SecurityProtocol ^ SecurityProtocolType.Tls12;
            }

            WriteVerbose(string.Format("Modified Security Protocol: {0}", ServicePointManager.SecurityProtocol));<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>

From PowerShell

#Set Security Protocol
$currentProtocol = [System.Net.ServicePointManager]::SecurityProtocol
Write-Verbose "Current Security Protocol: $currentProtocol"
if (-not $currentProtocol.HasFlag([System.Net.SecurityProtocolType]::Tls11))
{
    [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol  -bor [System.Net.SecurityProtocolType]::Tls11;
}
if (-not $currentProtocol.HasFlag([System.Net.SecurityProtocolType]::Tls12))
{
    [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol  -bor [System.Net.SecurityProtocolType]::Tls12;
}
$currentProtocol = [System.Net.ServicePointManager]::SecurityProtocol
Write-Verbose "Modified Security Protocol: $currentProtocol"

Hope this was helpful. Let me know if you have others solutions and if the above solutions work for you.

UI Automation for Dynamics 365 CE – EasyRepro (Part 2)

In this post I will cover how to get started using EasyRepro framework for Dynamics 365 CE. If you are new to UI Automation, take a look at my previous Introduction post.

Note the framework consists of a single solution that contains a sample project. If you just want to take a look and get an idea, you can download the source code from the GitHub project and take a look at the sample test project.

Unless you want to contribute to the framework or debug the framework code you are more likely to just consume the framework libraries and focus on building your tests. This is the scenario I will cover in this post.

Scenario

Login to CRM
Navigate to Sales/Contacts/Active Contacts
Create a new Contact
Save

Create a Unit Test project

You can use any unit testing framework you like. I will use MSTest. For this just add a new unit testing project to your solution as per below. Note you need to select .NET 4.7 as the Nuget packages doesn’t seem to install correctly with lower versions.

UIAutomationProject

Add the required NuGet packages

Add the EasyRepro library from the Nuget Gallery . Not sure if this published by MS. As an alternative you can compile the sample project from GitHub and add the Microsoft.Dynamics365.UIAutomation.Api and Microsoft.Dynamics365.UIAutomation.Browser DLLs as a reference).

EasyReproNuget

Below are all the package syou need along with the versions.

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Dynamics365.UIAutomation.Api" version="9.0.0" targetFramework="net47" />
  <package id="MSTest.TestAdapter" version="1.1.18" targetFramework="net461" />
  <package id="MSTest.TestFramework" version="1.1.18" targetFramework="net461" />
  <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net47" />
  <package id="Selenium.Chrome.WebDriver" version="2.31" targetFramework="net47" />
  <package id="Selenium.Support" version="3.5.1" targetFramework="net47" />
  <package id="Selenium.WebDriver" version="3.5.1" targetFramework="net47" />
  <package id="System.Diagnostics.DiagnosticSource" version="4.4.1" targetFramework="net47" />
</packages><span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>

Add a Test

As a standard unit test to your project.
CreateContactTest

First you will need your CRM URL, Username and Password. Below I am retrieving these from Environment variables as I didn’t want to check-in credentials to into source control. You can use configuration files. I strongly recommend that credentials are encrypted and securely stored.

        private readonly SecureString _username = Environment.GetEnvironmentVariable("CRMUser", EnvironmentVariableTarget.User).ToSecureString();
        private readonly SecureString _password = Environment.GetEnvironmentVariable("CRMPassword", EnvironmentVariableTarget.User).ToSecureString();
        private readonly Uri _xrmUri = new Uri(Environment.GetEnvironmentVariable("CRMUrl", EnvironmentVariableTarget.User));

Next you will need to define your browser requirements. In this instance I will use Chrome in Private (Incognito mode).

        private readonly BrowserOptions _options = new BrowserOptions
        {
            BrowserType = BrowserType.Chrome,
            PrivateMode = true,
            FireEvents = true
        };

The first step is normally to open a new browser instance and login to CRM. As you can see the below API make this very simple to achieve.

            using (var xrmBrowser = new XrmBrowser(_options))
            {
                xrmBrowser.LoginPage.Login(_xrmUri, _username, _password);
                xrmBrowser.GuidedHelp.CloseGuidedHelp();

Once CRM is open. You can interact with CRM page using the XrmBrowser object. As you can see below, there are different components for Navigation, Grids and CommandBar. Note you will need to add some think time between different calls to allow the browser to do its work.


                xrmBrowser.Navigation.OpenSubArea("Sales", "Contacts");

                xrmBrowser.ThinkTime(2000);
                xrmBrowser.Grid.SwitchView("Active Contacts");

                xrmBrowser.ThinkTime(1000);
                xrmBrowser.CommandBar.ClickCommand("New");

                xrmBrowser.ThinkTime(5000);

Once you are on the new contact page, you can interact with the CRM entity form through the Entity component. This allows you to set values on the form. This can be simple texts fields or even composite controls and lookups.

                var fields = new List<Field>
                {
                    new Field() {Id = "firstname", Value = "Wael"},
                    new Field() {Id = "lastname", Value = "Test"}
                };
                xrmBrowser.Entity.SetValue(new CompositeControl() { Id = "fullname", Fields = fields });
                xrmBrowser.Entity.SetValue("emailaddress1", "test@contoso.com");
                xrmBrowser.Entity.SetValue("mobilephone", "555-555-5555");
                xrmBrowser.Entity.SetValue("birthdate", DateTime.Parse("11/1/1980"));
                xrmBrowser.Entity.SetValue(new OptionSet { Name = "preferredcontactmethodcode", Value = "Email" });

Now you can save the form.

                xrmBrowser.CommandBar.ClickCommand("Save");
                xrmBrowser.ThinkTime(5000);

Finally I will take a screen shot. You can take these at any point in time during the test or if the test fails. This can be used as test evidence, troubleshooting failed tests or for spot checks.

                string screenShot = string.Format("{0}\\CreateNewContact.jpeg", TestContext.TestResultsDirectory);
                xrmBrowser.TakeWindowScreenShot(screenShot, ScreenshotImageFormat.Jpeg);
                TestContext.AddResultFile(screenShot);

Run the Test

If you run the test now the browser should navigate to CRM and perform the actions described in the scenario. You will normally add some verification at the end of the test to ensure the expected outcome was achieved and fail the test otherwise.

CreateContactTestResults
CreateContactScreenShot

You can find this code including any future updates on GitHub

As you can see it very easy to setup an automated UI test using EasyRepro. In the following posts I will cover more advanced topics on UI Automation.

UI Automation for Dynamics 365 CE – Introduction (Part 1)

This post is an introduction to UI Automation Testing for Dynamics 365 CE. I will cover the basic concepts. The next post will show how to get started and provide a practical example.

What is UI Automation?

As the name suggests, UI Automation is the automated testing that happens at the UI layer. Where as unit and integration tests interact with assemblies and APIs, UI tests interact with the actual application UI.

What is involved?

Typically the automated test will open the application UI which in our case is the Dynamics 365 CE web interface and then execute a series of scenarios as if it was the actual user performing the actions.

How does it work?

UI Automation tests typically use frameworks that have the ability to create an instance of a browser. Frameworks also provide APIs or drivers/adaptors that provide you with the ability to interact with the browser instance to perform actions such as navigating to page, filling out forms and clicking on UI elements. Selenium is one of the most widely used frameworks for testing web applications. You can find out more on the Selenium home page.

What framework should you use for Dynamics 365 CE?

There are many UI automation frameworks out there. If you already have a framework being used in your organisation for other web applications there is a good chance it might work well with Dynamics too. For this series I will be using EasyRepro. This is an open source Framework based on Selenium that was released by Microsoft early in 2017 and has recently been updated to support V9. Take look at the GitHub project for more information on the Framework.

What else you need to know about EasyRepro?

  • Tests are created using .NET, something most CRM developers are already familiar with which can help with adoption and ensure testing practices as part of your development life cycle.
  • It provides you with XrmBrowser object which is a POM (Page Object Model) abstraction on top of the CRM Page. So it gives you API for some of the mostly used actions by the user such as logging in to CRM, interacting with forms and navigation.
  • Future updates may include the ability generate code by recording actions or using IDE.
  • The framework is easy to use and samples on the GitHub project give you a quick start.

What tests you should be automating?

Before you get going with writing tests I would strongly recommend that you think carefully about what tests it makes sense to automate at UI layer. For this the test pyramid always comes handy.

TestPyramid

UI Tests provide very good coverage as they cover the UI and all the layers below such as integrations and any plug-ins you may have. However note the below:

  • UI tests take long to run
  • UI tests normally run less frequently and are further up in your DevOps pipeline.
  • UI tests take longer to develop and maintain

You should have a good number of units tests and integration tests which should provide good coverage for your components and integrations. You can use UI tests to cover UI level features that are not possible to test using Unit and Integration Tests. UI tests can also be used to perform high level smoke testing of your functionality or regression packs. Try to write UI tests once the functionality gets more stable to avoid changes these frequently.

Whats next?

In the next post I will show you how to get started and provide you with a practical examples.