Test-Driven Development workflow for .NET. Use when implementing features, fixing bugs, or writing new code. Guides RED-GREEN-REFACTOR cycle with proper test design.
Guides RED-GREEN-REFACTOR cycles when implementing features or fixing bugs. Creates failing tests first, then minimal code to pass, followed by refactoring with proper test doubles and AAA patterns.
/plugin marketplace add DoubleslashSE/claude-workflows/plugin install doubleslashse-dotnet-tdd-plugins-dotnet-tdd@DoubleslashSE/claude-workflowsThis skill is limited to using the following tools:
patterns.md ┌─────────────────────────────────────┐
│ │
│ ┌─────┐ ┌───────┐ ┌─────┐ │
│ │ RED │───▶│ GREEN │───▶│REFAC│──┘
│ └─────┘ └───────┘ └─────┘
│ │ │
│ │ Write failing test │
│ │ │
│ ▼ │
│ Make it pass (minimal) │
│ │
└──────────────────────────────┘
Improve design
{MethodUnderTest}_{Scenario}_{ExpectedBehavior}
Examples:
CreateOrder_WithValidItems_ReturnsOrderGetUser_WhenNotFound_ThrowsNotFoundExceptionCalculateTotal_WithDiscount_AppliesCorrectPercentage[Fact]
public void MethodName_Scenario_ExpectedResult()
{
// Arrange - Set up preconditions
var sut = new SystemUnderTest();
var input = CreateValidInput();
// Act - Execute the behavior
var result = sut.Execute(input);
// Assert - Verify outcome
Assert.Equal(expected, result);
}
// Unit Test - Tests single unit in isolation
[Fact]
public void Calculator_Add_ReturnsSumOfNumbers() { }
// Integration Test - Tests component interaction
[Fact]
public void OrderService_CreateOrder_PersistsToDatabase() { }
// Acceptance Test - Tests user scenarios
[Fact]
public void User_CanCompleteCheckout_WithValidCart() { }
// BAD - Over-engineering in GREEN phase
public decimal CalculateDiscount(Order order)
{
var strategy = _discountStrategyFactory.Create(order.CustomerType);
return strategy.Calculate(order, _configService.GetDiscountRules());
}
// GOOD - Minimal implementation for GREEN
public decimal CalculateDiscount(Order order)
{
return order.Total * 0.1m; // 10% discount
}
// Test expects specific value
[Fact]
public void GetGreeting_ReturnsHello()
{
var result = greeter.GetGreeting();
Assert.Equal("Hello", result);
}
// GREEN: Just return what the test expects
public string GetGreeting() => "Hello";
// Before: Long method
public void ProcessOrder(Order order)
{
// 50 lines of mixed concerns
}
// After: Single responsibility
public void ProcessOrder(Order order)
{
ValidateOrder(order);
CalculateTotals(order);
ApplyDiscounts(order);
PersistOrder(order);
NotifyCustomer(order);
}
// Dummy - Passed but never used
var dummyLogger = new Mock<ILogger>().Object;
// Stub - Provides canned answers
var stubRepo = new Mock<IUserRepository>();
stubRepo.Setup(r => r.GetById(1)).Returns(new User { Id = 1 });
// Spy - Records interactions
var spyNotifier = new SpyNotifier();
service.Execute();
Assert.True(spyNotifier.WasCalled);
// Mock - Verifies interactions
var mockNotifier = new Mock<INotifier>();
service.Execute();
mockNotifier.Verify(n => n.Send(It.IsAny<Message>()), Times.Once);
// Fake - Working implementation (in-memory)
var fakeRepo = new InMemoryUserRepository();
| Double | Use When |
|---|---|
| Dummy | Parameter required but unused |
| Stub | Need controlled return values |
| Spy | Need to verify calls were made |
| Mock | Need to verify specific interactions |
| Fake | Need realistic behavior without dependencies |
src/
├── MyApp.Domain/
│ └── Entities/
├── MyApp.Application/
│ └── Services/
└── MyApp.Infrastructure/
└── Repositories/
tests/
├── MyApp.Domain.Tests/
│ └── Entities/
├── MyApp.Application.Tests/
│ └── Services/
└── MyApp.Integration.Tests/
└── Repositories/
public class OrderServiceTests
{
private readonly Mock<IOrderRepository> _mockRepository;
private readonly Mock<INotificationService> _mockNotifier;
private readonly OrderService _sut;
public OrderServiceTests()
{
_mockRepository = new Mock<IOrderRepository>();
_mockNotifier = new Mock<INotificationService>();
_sut = new OrderService(_mockRepository.Object, _mockNotifier.Object);
}
[Fact]
public void CreateOrder_WithValidData_PersistsOrder() { }
[Fact]
public void CreateOrder_WithInvalidData_ThrowsValidationException() { }
}
// BAD: Testing implementation details
Assert.Equal(3, order.Items.Count);
// GOOD: Testing behavior
Assert.True(order.HasItems);
// BAD: Multiple assertions testing different behaviors
[Fact]
public void Order_Tests()
{
Assert.NotNull(order.Id);
Assert.Equal("Pending", order.Status);
Assert.True(order.Total > 0);
}
// GOOD: One logical assertion per test
[Fact]
public void NewOrder_HasPendingStatus()
{
Assert.Equal(OrderStatus.Pending, order.Status);
}
// BAD: Tests depending on order
[Fact]
public void Test1_CreateUser() { } // Creates user
[Fact]
public void Test2_GetUser() { } // Assumes user exists
// GOOD: Independent tests
[Fact]
public void GetUser_WhenExists_ReturnsUser()
{
var user = CreateUser(); // Arrange includes setup
var result = _sut.GetUser(user.Id);
Assert.NotNull(result);
}
# Run all tests
dotnet test
# Run with coverage
dotnet test /p:CollectCoverage=true
# Run specific test
dotnet test --filter "FullyQualifiedName~OrderServiceTests"
# Watch mode
dotnet watch test
[Fact] // Single test case
[Theory] // Parameterized test
[InlineData(1, 2)] // Test data
[Trait("Category", "Unit")] // Categorization
[Skip("Reason")] // Skip test
See patterns.md for advanced testing patterns.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.