Skip to content

optivem/optivem-testing-dotnet

Repository files navigation

Optivem Testing (.NET)

Commit Stage Acceptance Stage Release Stage

NuGet License

Optivem.Testing is an xUnit extension for channel-based data-driven testing. It enables you to run the same tests across multiple channels (UI, API, etc.) with automatic Cartesian product generation, test isolation markers, and time-dependent test support.

Features

Channel-Based Testing - Run tests across multiple channels (UI, API, etc.)
Cartesian Product Generation - Automatically combine channels with test data
Flexible Data Sources - Supports inline data, class data, and member data
Test Isolation - Mark tests that require isolation ([Isolated])
Time-Dependent Tests - Mark time-sensitive tests ([Time])
.NET 8+ - Modern .NET support

Installation

dotnet add package Optivem.Testing

Quick Start

Basic Channel Testing

Run the same test across multiple channels:

[Theory]
[ChannelData("UI", "API")]
public void CreateOrder_ShouldSucceed(Channel channel)
{
    // Arrange
    var order = new Order { ProductId = "P1", Quantity = 1 };
    
    // Act
    var result = channel.Type == "UI" 
        ? CreateOrderViaUI(order) 
        : CreateOrderViaAPI(order);
    
    // Assert
    result.Success.ShouldBeTrue();
}
// Generates 2 tests: CreateOrder_ShouldSucceed(UI), CreateOrder_ShouldSucceed(API)

Channel + Inline Data (Cartesian Product)

Combine channels with test data for comprehensive coverage:

[Theory]
[ChannelData("UI", "API")]
[ChannelInlineData("", "Country must not be empty")]
[ChannelInlineData("   ", "Country must not be empty")]
[ChannelInlineData("123", "Country must contain only letters")]
public void CreateOrder_InvalidCountry_ShouldFail(
    Channel channel, 
    string country, 
    string expectedError)
{
    // Test implementation validates error message
}
// Generates 6 tests: 2 channels × 3 data rows

Channel + Class Data

Use a class to provide test data:

public class InvalidCountryData : IEnumerable<object[]>
{
    public IEnumerator<object[]> GetEnumerator()
    {
        yield return new object[] { "", "Country must not be empty" };
        yield return new object[] { "   ", "Country must not be empty" };
        yield return new object[] { "123", "Country must contain only letters" };
    }
    
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

[Theory]
[ChannelData("UI", "API")]
[ChannelClassData(typeof(InvalidCountryData))]
public void CreateOrder_InvalidCountry_ShouldFail(
    Channel channel, 
    string country, 
    string expectedError)
{
    // Test implementation
}

Channel + Member Data

Use a method or property to provide test data:

public static IEnumerable<object[]> GetInvalidCountries()
{
    yield return new object[] { "", "Country must not be empty" };
    yield return new object[] { "   ", "Country must not be empty" };
    yield return new object[] { "123", "Country must contain only letters" };
}

[Theory]
[ChannelData("UI", "API")]
[ChannelMemberData(nameof(GetInvalidCountries))]
public void CreateOrder_InvalidCountry_ShouldFail(
    Channel channel, 
    string country, 
    string expectedError)
{
    // Test implementation
}

Test Isolation

Mark tests that require isolation from other tests:

[Fact]
[Isolated("Deletes all orders from database")]
public void ClearAllOrders_ShouldDeleteAllRecords()
{
    // This test modifies shared state
}

Filter isolated tests:

# Run ONLY isolated tests
dotnet test --filter "Category=isolated"

# Run all EXCEPT isolated tests
dotnet test --filter "Category!=isolated"

Time-Dependent Tests

Mark tests that depend on specific times:

[Fact]
[Time("2024-01-15T17:30:00Z")]
public void DiscountRate_ShouldBe15Percent_WhenAfter5pm()
{
    // Test implementation
}

Filter time-dependent tests:

# Run ONLY time-dependent tests
dotnet test --filter "Category=time"

# Run all EXCEPT time-dependent tests
dotnet test --filter "Category!=time"

Best Practices

  1. Channel Naming - Use consistent channel names across your test suite (e.g., "UI", "API", "CLI")
  2. Isolation - Always mark tests with side effects using [Isolated]
  3. Test Data - Use ChannelClassData or ChannelMemberData for complex test data
  4. Time Tests - [Time] tests are automatically marked as [Isolated]

Why Optivem.Testing?

  • Reduce Duplication - Write test logic once, run across all channels
  • Better Coverage - Cartesian products ensure comprehensive testing
  • Clear Intent - Attributes make test requirements explicit
  • Type Safety - Channel type prevents string typos
  • xUnit Compatible - Works seamlessly with existing xUnit tests

Requirements

  • .NET 8.0 or higher
  • xUnit 2.x

License

MIT License

Contributing

Contributions welcome! Please open an issue or submit a pull request.

Links


Built by Optivem

About

Optivem Testing (.NET)

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors 2

  •  
  •