Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Unit Tests

on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'

- name: Restore dependencies
run: dotnet restore tests/PepperDash.Essentials.Core.Tests/PepperDash.Essentials.Core.Tests.csproj

- name: Build tests
run: dotnet build tests/PepperDash.Essentials.Core.Tests/PepperDash.Essentials.Core.Tests.csproj --no-restore

- name: Run tests
run: dotnet test tests/PepperDash.Essentials.Core.Tests/PepperDash.Essentials.Core.Tests.csproj --no-build --verbosity normal --collect:"XPlat Code Coverage"

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
with:
files: ./tests/PepperDash.Essentials.Core.Tests/TestResults/*/coverage.cobertura.xml
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ bld/
[Ll]og/
[Ll]ogs/

# Test results and coverage
TestResults/
coverage/
*.trx
*.coverage
*.coveragexml
coverage.cobertura.xml
coverage-report/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
Expand Down
11 changes: 11 additions & 0 deletions PepperDash.Essentials.4Series.sln
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{02EA681E-C
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDash.Core", "src\PepperDash.Core\PepperDash.Core.csproj", "{E5336563-1194-501E-BC4A-79AD9283EF90}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C8EAB8E7-4F14-4E5C-8D23-1A3956D46DE8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash.Essentials.Core.Tests", "tests\PepperDash.Essentials.Core.Tests\PepperDash.Essentials.Core.Tests.csproj", "{A1234567-8901-2345-6789-ABCDEF012345}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug 4.7.2|Any CPU = Debug 4.7.2|Any CPU
Expand Down Expand Up @@ -79,6 +83,12 @@ Global
{E5336563-1194-501E-BC4A-79AD9283EF90}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E5336563-1194-501E-BC4A-79AD9283EF90}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E5336563-1194-501E-BC4A-79AD9283EF90}.Release|Any CPU.Build.0 = Release|Any CPU
{A1234567-8901-2345-6789-ABCDEF012345}.Debug 4.7.2|Any CPU.ActiveCfg = Debug|Any CPU
{A1234567-8901-2345-6789-ABCDEF012345}.Debug 4.7.2|Any CPU.Build.0 = Debug|Any CPU
{A1234567-8901-2345-6789-ABCDEF012345}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1234567-8901-2345-6789-ABCDEF012345}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1234567-8901-2345-6789-ABCDEF012345}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1234567-8901-2345-6789-ABCDEF012345}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -90,6 +100,7 @@ Global
{F6D362DE-2256-44B1-927A-8CE4705D839A} = {B24989D7-32B5-48D5-9AE1-5F3B17D25206}
{B438694F-8FF7-464A-9EC8-10427374471F} = {B24989D7-32B5-48D5-9AE1-5F3B17D25206}
{E5336563-1194-501E-BC4A-79AD9283EF90} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{A1234567-8901-2345-6789-ABCDEF012345} = {C8EAB8E7-4F14-4E5C-8D23-1A3956D46DE8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6907A4BF-7201-47CF-AAB1-3597F3B8E1C3}
Expand Down
188 changes: 188 additions & 0 deletions docs/testing/QuickStart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# Quick Start Guide: Unit Testing

This guide helps you get started with writing unit tests for PepperDash Essentials components.

## Prerequisites

- .NET 8 SDK
- Visual Studio 2022 or VS Code with C# extension

## Running Existing Tests

```bash
# Navigate to the test project
cd tests/PepperDash.Essentials.Core.Tests

# Run all tests
dotnet test

# Run with coverage
dotnet test --collect:"XPlat Code Coverage"
```

## Creating Your First Test

### 1. Identify the Component

Choose a component that has business logic you want to test. Look for classes that:
- Have clear inputs and outputs
- Contain conditional logic or algorithms
- Are used by multiple parts of the system

### 2. Create Test File

Create a new test file in `tests/PepperDash.Essentials.Core.Tests/Unit/`:

```csharp
using PepperDash.Essentials.Core.Tests.Abstractions;

namespace PepperDash.Essentials.Core.Tests.Unit
{
public class YourComponentTests
{
[Fact]
public void YourMethod_WithValidInput_ReturnsExpectedResult()
{
// Arrange
var component = new YourComponent();
var input = "test data";

// Act
var result = component.YourMethod(input);

// Assert
Assert.Equal("expected result", result);
}
}
}
```

### 3. Abstract Dependencies

If your component uses Crestron SDK or other external dependencies:

```csharp
// Create interface in Abstractions/
public interface IYourDependency
{
string DoSomething(string input);
}

// Modify your component to use the interface
public class YourComponent
{
private readonly IYourDependency _dependency;

public YourComponent(IYourDependency dependency)
{
_dependency = dependency;
}

public string YourMethod(string input)
{
return _dependency.DoSomething(input);
}
}

// Test with mocks
[Fact]
public void YourMethod_CallsDependency_ReturnsResult()
{
// Arrange
var mockDependency = new Mock<IYourDependency>();
mockDependency.Setup(x => x.DoSomething("input")).Returns("output");
var component = new YourComponent(mockDependency.Object);

// Act
var result = component.YourMethod("input");

// Assert
Assert.Equal("output", result);
mockDependency.Verify(x => x.DoSomething("input"), Times.Once);
}
```

## Testing Patterns

### Testing Exceptions

```csharp
[Fact]
public void Constructor_WithNullDependency_ThrowsArgumentNullException()
{
// Act & Assert
Assert.Throws<ArgumentNullException>(() => new YourComponent(null));
}
```

### Testing Async Methods

```csharp
[Fact]
public async Task YourAsyncMethod_WithValidInput_ReturnsExpectedResult()
{
// Arrange
var component = new YourComponent();

// Act
var result = await component.YourAsyncMethod();

// Assert
Assert.True(result);
}
```

### Testing Collections

```csharp
[Fact]
public void GetItems_ReturnsExpectedCount()
{
// Arrange
var component = new YourComponent();

// Act
var items = component.GetItems();

// Assert
Assert.Equal(3, items.Count());
Assert.Contains(items, x => x.Name == "Expected Item");
}
```

## Common Mistakes to Avoid

1. **Testing Implementation Details** - Test behavior, not internal implementation
2. **Overly Complex Tests** - Keep tests simple and focused on one thing
3. **Not Testing Edge Cases** - Include null values, empty collections, boundary conditions
4. **Ignoring Test Performance** - Tests should run quickly to enable fast feedback

## Debugging Tests

### In Visual Studio
- Set breakpoints in test methods
- Use Test Explorer to run individual tests
- Check test output window for detailed information

### From Command Line
```bash
# Run specific test
dotnet test --filter "YourComponentTests.YourMethod_WithValidInput_ReturnsExpectedResult"

# Run with detailed output
dotnet test --verbosity diagnostic
```

## Next Steps

1. **Review Examples** - Look at `TestableActionSequenceTests.cs` for comprehensive examples
2. **Start Small** - Begin with simple components and build up complexity
3. **Read Documentation** - Check `docs/testing/README.md` for detailed patterns
4. **Get Feedback** - Have your tests reviewed by team members

## Need Help?

- Check existing test examples in the codebase
- Review the full testing documentation
- Ask team members for guidance on complex scenarios
- Consider pair programming for your first few tests
Loading
Loading