![]()
1. Introduction to EasyRepro for Dynamics 365 Testing
What is EasyRepro?
EasyRepro is an open-source test automation framework specifically designed for Microsoft Dynamics 365 applications. Developed by Microsoft engineers, it provides:
- C#-based testing library for Dynamics 365 CE/F&O
- Selenium WebDriver integration
- Pre-built methods for common CRM operations
- Cross-browser testing capabilities
Why Use EasyRepro Over Generic Testing Tools?
✔ Native Dynamics 365 element locators
✔ Optimized wait handlers for async processes
✔ Built-in XPath generators for CRM controls
✔ Active community support (GitHub, MS Docs)
2. Technical Architecture
Core Components
graph TD
A[Test Scripts] --> B[EasyRepro API]
B --> C[Selenium WebDriver]
C --> D[Browser]
D --> E[Dynamics 365]
Supported Technologies
- Languages: C# (.NET Core/.NET 5+)
- Testing Frameworks: MSTest, NUnit, xUnit
- CI/CD: Azure DevOps, GitHub Actions
- Reporting: ExtentReports, Allure
3. Environment Setup
Prerequisites
- Development Environment:
- Visual Studio 2019/2022
- .NET 5+ SDK
- Testing Tools:
- Selenium WebDriver
- Browser drivers (Chrome, Edge, Firefox)
- Dynamics 365 Access:
- Test environment URL
- Service account credentials
Installation Steps
# Clone the repository
git clone https://github.com/microsoft/EasyRepro
# Install NuGet packages
dotnet add package Microsoft.Dynamics365.UIAutomation.Api
dotnet add package Selenium.WebDriver
4. Writing Your First Test
Basic Test Structure
[TestClass]
public class AccountTests : TestBase
{
[TestMethod]
public void CreateNewAccount()
{
using (var client = new WebClient(TestSettings.Options))
{
// Login to D365
client.Browser.LoginPage.Login(
TestSettings.Username,
TestSettings.Password);
// Navigate to Accounts
client.Browser.Navigation.OpenSubArea("Sales", "Accounts");
// Create new account
client.Browser.CommandBar.ClickCommand("New");
// Set field values
client.Browser.Entity.SetValue("name", "Test Account");
client.Browser.Entity.SetValue("telephone1", "555-1234");
// Save and verify
client.Browser.CommandBar.ClickCommand("Save");
Assert.IsTrue(client.Browser.Entity.GetValue("name") == "Test Account");
}
}
}
Key Methods
| Method | Purpose | Example |
|---|---|---|
Login() | Authenticate to D365 | Login(username, password) |
SetValue() | Populate fields | SetValue("fieldname", value) |
GetValue() | Read field values | GetValue("fieldname") |
ClickCommand() | Toolbar actions | ClickCommand("Save & Close") |
5. Advanced Testing Scenarios
Handling Complex UI Elements
// Working with lookups
client.Browser.Entity.SelectLookup("primarycontactid");
client.Browser.Lookup.Search("John Doe");
client.Browser.Lookup.Add();
// Dealing with business process flows
client.Browser.BPF.SelectStage("Qualify");
client.Browser.BPF.NextStage();
// Testing dialogs
client.Browser.Dialogs.ConfirmationDialog(true);
Data-Driven Testing
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV",
"TestData\\Accounts.csv", "Accounts#csv", DataAccessMethod.Sequential)]
[TestMethod]
public void CreateAccount_DataDriven()
{
var accountName = TestContext.DataRow["Name"].ToString();
var phone = TestContext.DataRow["Phone"].ToString();
client.Browser.Entity.SetValue("name", accountName);
client.Browser.Entity.SetValue("telephone1", phone);
}
6. Best Practices for Reliable Tests
Element Locator Strategies
- Prefer API methods over direct XPath
// Good
client.Browser.Entity.SetValue("name", "Acme");
// Avoid
driver.FindElement(By.XPath("//input[@aria-label='Account Name']"));
- Custom wait handlers for Dynamics controls
client.Browser.Driver.WaitUntilClickable(
By.XPath("//button[@title='Save']"),
TimeSpan.FromSeconds(30));
Test Stability Techniques
- Retry mechanisms for flaky tests
- Environment checks before execution
- Screenshot capture on failures
7. Integration with CI/CD Pipelines
Azure DevOps Example
steps:
- task: DotNetCoreCLI@2
inputs:
command: 'test'
projects: '**/*Tests.csproj'
arguments: '--configuration Release --collect "Code coverage"'
- task: PublishTestResults@2
inputs:
testResultsFormat: 'VSTest'
testResultsFiles: '**/*.trx'
Parallel Execution Setup
[AssemblyInitialize]
public static void Setup(TestContext context)
{
TestSettings.Options = new BrowserOptions
{
BrowserType = BrowserType.Chrome,
Headless = true,
RemoteBrowser = false,
UCITestMode = true,
DriversPath = @"C:\WebDrivers"
};
}
8. Reporting and Analysis
Generating HTML Reports
[TestInitialize]
public void Init()
{
_extent = new ExtentReports();
_test = _extent.CreateTest(TestContext.TestName);
}
[TestCleanup]
public void Cleanup()
{
var status = TestContext.CurrentTestOutcome;
_test.Log(status, "Test completed");
_extent.Flush();
}
Interpreting Test Results
- Failure analysis: DOM snapshots vs. test steps
- Performance metrics: Page load times
- Environment logging: Browser versions, URLs
9. Common Challenges and Solutions
| Challenge | Solution |
|---|---|
| IFrame detection issues | Use SwitchToDefaultContent() |
| Random popups | Implement dismissal handlers |
| Async save operations | Custom wait conditions |
| MFA requirements | Use test accounts without MFA |
10. Future of Dynamics 365 Testing
Upcoming Features
- Power Platform test automation integration
- AI-powered test maintenance
- Codeless test authoring
Community Resources
Implementation Roadmap
- Pilot Phase (2-4 weeks)
- Setup test infrastructure
- Create 10-20 core test cases
- Integrate with build pipeline
- Expansion Phase (1-3 months)
- Cover critical business processes
- Implement data-driven testing
- Add CI/CD integration
- Maturity Phase (Ongoing)
- Maintenance strategy
- Test coverage metrics
- Flaky test management
Pro Tip: Start with happy path scenarios before tackling edge cases, and always include test data cleanup in your automation.
// Example cleanup method
[TestCleanup]
public void Cleanup()
{
try
{
if (TestContext.CurrentTestOutcome == UnitTestOutcome.Passed)
{
client.Browser.Entity.Delete();
}
}
catch { /* Log error */ }
}
