Table of Contents

Data-Driven Testing Examples

Data-driven testing is a powerful approach that allows you to execute the same test logic with multiple sets of input data. This section provides comprehensive examples for implementing data-driven testing patterns with the Ranorex API.

Overview

Data-driven testing separates test logic from test data, enabling:

  • Scalability: Test the same functionality with hundreds of data sets
  • Maintainability: Update test data without modifying code
  • Coverage: Test edge cases and boundary conditions systematically
  • Efficiency: Reduce code duplication and maintenance overhead

Table of Contents

Database-Driven

Connect to databases to retrieve test data dynamically.

SQL Server Integration

using System;
using System.Data;
using System.Data.SqlClient;
using Ranorex;
using Ranorex.Core;

public class DatabaseDrivenTest
{
    private string connectionString = "Server=localhost;Database=TestData;Integrated Security=true;";
    
    public void RunDatabaseDrivenTest()
    {
        Host.Initialize();
        
        try
        {
            var testData = GetTestDataFromDatabase();
            
            foreach (DataRow row in testData.Rows)
            {
                ExecuteTestCase(
                    username: row["Username"].ToString(),
                    password: row["Password"].ToString(),
                    expectedResult: row["ExpectedResult"].ToString()
                );
            }
        }
        catch (Exception ex)
        {
            Report.Failure("Database Test", $"Failed: {ex.Message}");
            throw;
        }
        finally
        {
            Host.Shutdown();
        }
    }
    
    private DataTable GetTestDataFromDatabase()
    {
        using (var connection = new SqlConnection(connectionString))
        {
            connection.Open();
            
            var command = new SqlCommand(@"
                SELECT Username, Password, ExpectedResult 
                FROM LoginTestData 
                WHERE IsActive = 1", connection);
            
            var adapter = new SqlDataAdapter(command);
            var dataTable = new DataTable();
            adapter.Fill(dataTable);
            
            Report.Info("Database", $"Retrieved {dataTable.Rows.Count} test cases");
            return dataTable;
        }
    }
    
    private void ExecuteTestCase(string username, string password, string expectedResult)
    {
        try
        {
            // Perform login action
            var repo = MyAppRepository.Instance;
            repo.LoginDialog.UsernameField.PressKeys(username);
            repo.LoginDialog.PasswordField.PressKeys(password);
            repo.LoginDialog.LoginButton.Click();
            
            // Validate result
            if (expectedResult == "Success")
            {
                Validate.IsTrue(repo.Dashboard.WelcomeMessage.Visible, 
                    $"Login should succeed for user: {username}");
                Report.Success("Login Test", $"User {username} logged in successfully");
            }
            else
            {
                Validate.IsTrue(repo.LoginDialog.ErrorMessage.Visible, 
                    $"Login should fail for user: {username}");
                Report.Success("Login Test", $"Login correctly failed for user: {username}");
            }
        }
        catch (Exception ex)
        {
            Report.Failure("Login Test", $"Test failed for user {username}: {ex.Message}");
        }
    }
}

MySQL Integration

using MySql.Data.MySqlClient;
using System.Collections.Generic;

public class MySqlDataProvider
{
    private string connectionString = "Server=localhost;Database=testdb;Uid=testuser;Pwd=password;";
    
    public List<TestCase> GetTestCases(string testSuite)
    {
        var testCases = new List<TestCase>();
        
        using (var connection = new MySqlConnection(connectionString))
        {
            connection.Open();
            
            var command = new MySqlCommand(@"
                SELECT tc.TestCaseId, tc.TestName, tc.InputData, tc.ExpectedOutput
                FROM TestCases tc
                INNER JOIN TestSuites ts ON tc.TestSuiteId = ts.TestSuiteId
                WHERE ts.SuiteName = @suiteName AND tc.IsEnabled = 1
                ORDER BY tc.ExecutionOrder", connection);
            
            command.Parameters.AddWithValue("@suiteName", testSuite);
            
            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    testCases.Add(new TestCase
                    {
                        Id = reader.GetInt32("TestCaseId"),
                        Name = reader.GetString("TestName"),
                        InputData = reader.GetString("InputData"),
                        ExpectedOutput = reader.GetString("ExpectedOutput")
                    });
                }
            }
        }
        
        Report.Info("MySQL Data", $"Loaded {testCases.Count} test cases for suite: {testSuite}");
        return testCases;
    }
}

public class TestCase
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string InputData { get; set; }
    public string ExpectedOutput { get; set; }
}

File Processing

Process various file formats for test data input.

Excel Data Integration

using System;
using System.Data;
using System.IO;
using ExcelDataReader;
using Ranorex;

public class ExcelDataDrivenTest
{
    public void RunExcelDrivenTest(string excelFilePath)
    {
        Host.Initialize();
        
        try
        {
            var testData = ReadExcelData(excelFilePath);
            
            foreach (DataRow row in testData.Rows)
            {
                var testCase = new
                {
                    TestName = row["TestName"].ToString(),
                    ProductName = row["ProductName"].ToString(),
                    Quantity = Convert.ToInt32(row["Quantity"]),
                    Price = Convert.ToDecimal(row["Price"]),
                    ExpectedTotal = Convert.ToDecimal(row["ExpectedTotal"])
                };
                
                ExecuteShoppingCartTest(testCase.ProductName, testCase.Quantity, 
                    testCase.Price, testCase.ExpectedTotal);
            }
        }
        catch (Exception ex)
        {
            Report.Failure("Excel Test", $"Failed: {ex.Message}");
            throw;
        }
        finally
        {
            Host.Shutdown();
        }
    }
    
    private DataTable ReadExcelData(string filePath)
    {
        using (var stream = File.Open(filePath, FileMode.Open, FileAccess.Read))
        {
            using (var reader = ExcelReaderFactory.CreateReader(stream))
            {
                var result = reader.AsDataSet(new ExcelDataSetConfiguration()
                {
                    ConfigureDataTable = (_) => new ExcelDataTableConfiguration()
                    {
                        UseHeaderRow = true
                    }
                });
                
                return result.Tables[0];
            }
        }
    }
    
    private void ExecuteShoppingCartTest(string productName, int quantity, 
        decimal price, decimal expectedTotal)
    {
        try
        {
            var repo = ECommerceRepository.Instance;
            
            // Add product to cart
            repo.ProductPage.SearchField.PressKeys(productName);
            repo.ProductPage.SearchButton.Click();
            repo.ProductPage.ProductItem.Click();
            
            // Set quantity
            repo.ProductDetails.QuantityField.PressKeys(quantity.ToString());
            repo.ProductDetails.AddToCartButton.Click();
            
            // Verify total
            var actualTotal = decimal.Parse(repo.Cart.TotalAmount.Text.Replace("$", ""));
            
            Validate.AreEqual(expectedTotal, actualTotal, 
                $"Total should be {expectedTotal:C} for {quantity} x {productName}");
            
            Report.Success("Shopping Cart", 
                $"Product {productName} test passed: {quantity} x {price:C} = {actualTotal:C}");
        }
        catch (Exception ex)
        {
            Report.Failure("Shopping Cart", $"Test failed for {productName}: {ex.Message}");
        }
    }
}

CSV Data Processing

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Ranorex;

public class CsvDataProvider
{
    public IEnumerable<UserTestData> ReadUserData(string csvFilePath)
    {
        var users = new List<UserTestData>();
        
        using (var reader = new StreamReader(csvFilePath))
        {
            // Skip header row
            reader.ReadLine();
            
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                var values = ParseCsvLine(line);
                
                if (values.Length >= 6)
                {
                    users.Add(new UserTestData
                    {
                        FirstName = values[0],
                        LastName = values[1],
                        Email = values[2],
                        Phone = values[3],
                        UserType = values[4],
                        ExpectedValidation = bool.Parse(values[5])
                    });
                }
            }
        }
        
        Report.Info("CSV Data", $"Loaded {users.Count} user records from {csvFilePath}");
        return users;
    }
    
    private string[] ParseCsvLine(string line)
    {
        var result = new List<string>();
        bool inQuotes = false;
        string currentField = "";
        
        for (int i = 0; i < line.Length; i++)
        {
            char c = line[i];
            
            if (c == '"')
            {
                inQuotes = !inQuotes;
            }
            else if (c == ',' && !inQuotes)
            {
                result.Add(currentField);
                currentField = "";
            }
            else
            {
                currentField += c;
            }
        }
        
        result.Add(currentField);
        return result.ToArray();
    }
}

public class UserTestData
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    public string UserType { get; set; }
    public bool ExpectedValidation { get; set; }
}

JSON Data Integration

using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using Ranorex;

public class JsonDataDrivenTest
{
    public void RunJsonDrivenTest(string jsonFilePath)
    {
        Host.Initialize();
        
        try
        {
            var testScenarios = LoadTestScenarios(jsonFilePath);
            
            foreach (var scenario in testScenarios)
            {
                Report.Info("Test Scenario", $"Executing: {scenario.Name}");
                
                foreach (var step in scenario.Steps)
                {
                    ExecuteTestStep(step);
                }
                
                ValidateScenarioResult(scenario);
            }
        }
        catch (Exception ex)
        {
            Report.Failure("JSON Test", $"Failed: {ex.Message}");
            throw;
        }
        finally
        {
            Host.Shutdown();
        }
    }
    
    private List<TestScenario> LoadTestScenarios(string filePath)
    {
        var json = File.ReadAllText(filePath);
        var data = JsonConvert.DeserializeObject<TestData>(json);
        
        Report.Info("JSON Data", $"Loaded {data.Scenarios.Count} test scenarios");
        return data.Scenarios;
    }
    
    private void ExecuteTestStep(TestStep step)
    {
        switch (step.Action.ToLower())
        {
            case "click":
                ExecuteClickAction(step);
                break;
            case "type":
                ExecuteTypeAction(step);
                break;
            case "wait":
                ExecuteWaitAction(step);
                break;
            case "validate":
                ExecuteValidateAction(step);
                break;
            default:
                throw new InvalidOperationException($"Unknown action: {step.Action}");
        }
    }
    
    private void ExecuteClickAction(TestStep step)
    {
        var element = Host.Local.FindSingle(step.Target);
        element.Click();
        Report.Info("Action", $"Clicked: {step.Target}");
    }
    
    private void ExecuteTypeAction(TestStep step)
    {
        var element = Host.Local.FindSingle(step.Target);
        element.PressKeys(step.Data);
        Report.Info("Action", $"Typed '{step.Data}' into: {step.Target}");
    }
    
    private void ExecuteWaitAction(TestStep step)
    {
        var timeout = TimeSpan.FromMilliseconds(int.Parse(step.Data));
        System.Threading.Thread.Sleep(timeout);
        Report.Info("Action", $"Waited: {step.Data}ms");
    }
    
    private void ExecuteValidateAction(TestStep step)
    {
        var element = Host.Local.FindSingle(step.Target);
        var actualValue = element.GetAttributeValueText(step.Attribute ?? "Text");
        
        Validate.AreEqual(step.ExpectedValue, actualValue, 
            $"Validation failed for {step.Target}");
        Report.Success("Validation", 
            $"Validated {step.Target}: Expected='{step.ExpectedValue}', Actual='{actualValue}'");
    }
    
    private void ValidateScenarioResult(TestScenario scenario)
    {
        foreach (var validation in scenario.Validations)
        {
            ExecuteValidateAction(validation);
        }
    }
}

public class TestData
{
    public List<TestScenario> Scenarios { get; set; }
}

public class TestScenario
{
    public string Name { get; set; }
    public string Description { get; set; }
    public List<TestStep> Steps { get; set; }
    public List<TestStep> Validations { get; set; }
}

public class TestStep
{
    public string Action { get; set; }
    public string Target { get; set; }
    public string Data { get; set; }
    public string Attribute { get; set; }
    public string ExpectedValue { get; set; }
}

Configuration-Based Testing

Use configuration files to drive test execution parameters.

XML Configuration

using System;
using System.Xml.Linq;
using System.Linq;
using Ranorex;

public class XmlConfigDrivenTest
{
    public void RunConfigDrivenTest(string configPath)
    {
        Host.Initialize();
        
        try
        {
            var config = LoadConfiguration(configPath);
            
            foreach (var testGroup in config.TestGroups)
            {
                Report.Info("Test Group", $"Executing: {testGroup.Name}");
                
                foreach (var test in testGroup.Tests)
                {
                    ExecuteConfiguredTest(test, testGroup.Settings);
                }
            }
        }
        catch (Exception ex)
        {
            Report.Failure("Config Test", $"Failed: {ex.Message}");
            throw;
        }
        finally
        {
            Host.Shutdown();
        }
    }
    
    private TestConfiguration LoadConfiguration(string configPath)
    {
        var doc = XDocument.Load(configPath);
        var config = new TestConfiguration();
        
        config.TestGroups = doc.Root.Elements("TestGroup")
            .Select(group => new TestGroup
            {
                Name = group.Attribute("name").Value,
                Settings = group.Elements("Setting").ToDictionary(
                    s => s.Attribute("key").Value,
                    s => s.Attribute("value").Value
                ),
                Tests = group.Elements("Test").Select(test => new ConfiguredTest
                {
                    Name = test.Attribute("name").Value,
                    Type = test.Attribute("type").Value,
                    Parameters = test.Elements("Parameter").ToDictionary(
                        p => p.Attribute("name").Value,
                        p => p.Attribute("value").Value
                    )
                }).ToList()
            }).ToList();
        
        return config;
    }
    
    private void ExecuteConfiguredTest(ConfiguredTest test, Dictionary<string, string> settings)
    {
        switch (test.Type.ToLower())
        {
            case "login":
                ExecuteLoginTest(test.Parameters, settings);
                break;
            case "form":
                ExecuteFormTest(test.Parameters, settings);
                break;
            case "navigation":
                ExecuteNavigationTest(test.Parameters, settings);
                break;
            default:
                throw new InvalidOperationException($"Unknown test type: {test.Type}");
        }
    }
}

public class TestConfiguration
{
    public List<TestGroup> TestGroups { get; set; } = new List<TestGroup>();
}

public class TestGroup
{
    public string Name { get; set; }
    public Dictionary<string, string> Settings { get; set; } = new Dictionary<string, string>();
    public List<ConfiguredTest> Tests { get; set; } = new List<ConfiguredTest>();
}

public class ConfiguredTest
{
    public string Name { get; set; }
    public string Type { get; set; }
    public Dictionary<string, string> Parameters { get; set; } = new Dictionary<string, string>();
}

API Data Integration

Retrieve test data from REST APIs for dynamic testing scenarios.

REST API Data Provider

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Ranorex;

public class ApiDataDrivenTest
{
    private readonly HttpClient httpClient = new HttpClient();
    
    public async Task RunApiDrivenTestAsync()
    {
        Host.Initialize();
        
        try
        {
            var testData = await GetTestDataFromApiAsync();
            
            foreach (var data in testData)
            {
                await ExecuteApiTestCaseAsync(data);
            }
        }
        catch (Exception ex)
        {
            Report.Failure("API Test", $"Failed: {ex.Message}");
            throw;
        }
        finally
        {
            Host.Shutdown();
            httpClient.Dispose();
        }
    }
    
    private async Task<List<ApiTestData>> GetTestDataFromApiAsync()
    {
        var response = await httpClient.GetAsync("https://api.example.com/testdata");
        response.EnsureSuccessStatusCode();
        
        var json = await response.Content.ReadAsStringAsync();
        var testData = JsonConvert.DeserializeObject<List<ApiTestData>>(json);
        
        Report.Info("API Data", $"Retrieved {testData.Count} test cases from API");
        return testData;
    }
    
    private async Task ExecuteApiTestCaseAsync(ApiTestData testData)
    {
        try
        {
            // Execute the test case using the API data
            var repo = MyAppRepository.Instance;
            
            // Navigate to the test page
            repo.Application.NavigateToUrl(testData.TargetUrl);
            
            // Fill form with API data
            foreach (var field in testData.FormFields)
            {
                var element = repo.Form.FindChild(field.Key);
                element.PressKeys(field.Value);
            }
            
            // Submit and validate
            repo.Form.SubmitButton.Click();
            
            // Validate against expected API response
            var validationResult = await ValidateAgainstApiAsync(testData.ValidationEndpoint, testData.Id);
            
            if (validationResult)
            {
                Report.Success("API Test", $"Test case {testData.Id} passed validation");
            }
            else
            {
                Report.Failure("API Test", $"Test case {testData.Id} failed validation");
            }
        }
        catch (Exception ex)
        {
            Report.Failure("API Test", $"Test case {testData.Id} failed: {ex.Message}");
        }
    }
    
    private async Task<bool> ValidateAgainstApiAsync(string endpoint, string testId)
    {
        var response = await httpClient.GetAsync($"{endpoint}?testId={testId}");
        
        if (!response.IsSuccessStatusCode)
            return false;
        
        var json = await response.Content.ReadAsStringAsync();
        var result = JsonConvert.DeserializeObject<ValidationResult>(json);
        
        return result.IsValid;
    }
}

public class ApiTestData
{
    public string Id { get; set; }
    public string TargetUrl { get; set; }
    public Dictionary<string, string> FormFields { get; set; }
    public string ValidationEndpoint { get; set; }
}

public class ValidationResult
{
    public bool IsValid { get; set; }
    public string Message { get; set; }
}

Best Practices

Data Management

public class DataDrivenBestPractices
{
    // 1. Use data abstraction layers
    public interface ITestDataProvider
    {
        IEnumerable<TestCaseData> GetTestData(string source);
        void UpdateTestResult(string testId, TestResult result);
    }
    
    // 2. Implement proper error handling
    public void SafeDataRetrieval()
    {
        try
        {
            var data = GetTestData();
            // Process data
        }
        catch (DataException ex)
        {
            Report.Error("Data", $"Data retrieval failed: {ex.Message}");
            // Fallback to static data or skip test
        }
    }
    
    // 3. Use parameterized queries for security
    public DataTable GetSecureData(string userId)
    {
        var query = "SELECT * FROM TestData WHERE UserId = @userId";
        // Use parameterized query implementation
        return ExecuteParameterizedQuery(query, new { userId });
    }
    
    // 4. Implement data validation
    public bool ValidateTestData(TestCaseData data)
    {
        if (string.IsNullOrEmpty(data.TestName))
        {
            Report.Warn("Data Validation", "Test name is empty");
            return false;
        }
        
        if (data.InputParameters == null || data.InputParameters.Count == 0)
        {
            Report.Warn("Data Validation", "No input parameters provided");
            return false;
        }
        
        return true;
    }
    
    // 5. Use data cleanup strategies
    public void CleanupTestData()
    {
        // Remove temporary test data
        // Reset database to known state
        // Clear generated files
    }
}

Performance Optimization

  • Connection Pooling: Reuse database connections
  • Batch Processing: Group similar operations
  • Lazy Loading: Load data only when needed
  • Caching: Cache frequently used test data
  • Parallel Execution: Run independent tests concurrently

Security Considerations

  • Credential Management: Store sensitive data securely
  • Data Encryption: Encrypt sensitive test data
  • Access Control: Limit access to test data sources
  • Audit Logging: Track data access and modifications

Next Steps: Choose a data source that matches your testing environment and adapt the examples to your specific application requirements.