| name | dotnet-testing-unit-test-fundamentals |
| description | .NET unit test fundamentals and FIRST principles specialized skill. Used when creating unit tests, understanding testing basics, learning 3A Pattern, and mastering testing best practices. Covers FIRST principles, AAA Pattern, Fact/Theory, testing pyramid, etc.
Keywords: unit test, unit test, unit testing, test fundamentals, testing fundamentals, FIRST principle, FIRST principle, 3A pattern, AAA pattern, Arrange Act Assert, Fact, Theory, InlineData, how to write tests, testing best practices, create unit test
|
| license | MIT |
| targets | ["*"] |
| category | testing |
| subcategory | fundamentals |
| tags | ["dotnet","testing","fundamentals","unit-test","xunit","first-principles"] |
| metadata | {"author":"Kevin Tseng","version":"1.0.0"} |
| related_skills | ["dotnet-testing-test-naming-conventions","dotnet-testing-xunit-project-setup","dotnet-testing-awesome-assertions-guide"] |
| claudecode | {} |
| opencode | {} |
| codexcli | {"short-description":".NET skill guidance for dotnet-testing-unit-test-fundamentals"} |
| copilot | {} |
| geminicli | {} |
| antigravity | {} |
Source: kevintsengtw/dotnet-testing-agent-skills (MIT). Ported into dotnet-agent-harness.
.NET Unit Test Fundamentals Guide
Applicable Scenarios
Use this skill when asked to perform the following tasks:
- Create unit tests for .NET classes or methods
- Review or improve existing test quality
- Design test cases following FIRST principles
- Explain test naming conventions and best practices
- Write tests using xUnit
FIRST Principles
Every unit test must conform to the following principles:
F - Fast
Test execution time should be in milliseconds, not dependent on external resources.
[Fact]
public void Add_WithInput1And2_ShouldReturn3()
{
var calculator = new Calculator();
var result = calculator.Add(1, 2);
Assert.Equal(3, result);
}
```text
### I - Independent
Tests should not have dependencies, each test creates a new instance.
```csharp
[Fact]
public void Increment_StartingFrom0_ShouldReturn1()
{
var counter = new Counter();
counter.Increment();
Assert.Equal(1, counter.Value);
}
```text
### R - Repeatable
Should produce the same results in any environment, not dependent on external state.
```csharp
[Fact]
{
counter = Counter();
counter.Increment();
counter.Increment();
counter.Increment();
Assert.Equal(, counter.Value);
}
```text
Test results should be clearly pass fail, clear assertions.
```csharp
[]
{
emailHelper = EmailHelper();
result = emailHelper.IsValidEmail();
Assert.True(result);
}
```text
Tests should be written before simultaneously production code, ensuring code testability.
Every test method **must** follow the Arrange-Act-Assert pattern:
```csharp
[]
{
calculator = Calculator();
a = ;
b = ;
expected = ;
result = calculator.Add(a, b);
Assert.Equal(expected, result);
}
```text
| Block | Responsibility | Notes |
| ----------- | ------------------------------ | ----------------------------------- |
| **Arrange** | Prepare objects, data, Mocks needed testing | Use `` to declare constant values, improve readability |
| **Act** | Execute the method under test | Usually only one line, calling the method under test |
| **Assert** | Verify results | Each test only validates one behavior |
Use the following format to name test methods:
```text
[]_[TestScenario]_[ExpectedBehavior]
```text
| Method Name | Description |
| ---------------------------------------------- | ------------ |
| `Add_WithInput1And2_ShouldReturn3` | Test normal input |
| `Add_WithNegativeAndPositiveNumbers_ShouldReturnCorrectResult` | Test boundary conditions |
| `Divide_WithInput10And0_ShouldThrowDivideByZeroException` | Test exception |
| `IsValidEmail_WithNullInput_ShouldReturnFalse` | Test invalid input |
| `GetDomain_WithValidEmail_ShouldReturnDomainName` | Test |
> 💡 **Tip**: Using Chinese naming can make test reports more readable, especially during team communication.
Used testing a single scenario:
```csharp
[]
{
calculator = Calculator();
result = calculator.Add(, );
Assert.Equal(, result);
}
```text
Used testing multiple input combinations:
```csharp
[]
[]
[]
[]
[]
{
calculator = Calculator();
result = calculator.Add(a, b);
Assert.Equal(expected, result);
}
```text
```csharp
[]
[]
[]
[]
[]
{
emailHelper = EmailHelper();
result = emailHelper.IsValidEmail(invalidEmail);
Assert.False(result);
}
```text
Test expected exception throwing scenarios:
```csharp
[]
{
calculator = Calculator();
dividend = m;
divisor = m;
exception = Assert.Throws<DivideByZeroException>(
() => calculator.Divide(dividend, divisor)
);
Assert.Equal(, exception.Message);
}
```text
Recommended project structure:
```text
Solution/
├── src/
│ └── MyProject/
│ ├── Calculator.cs
│ └── MyProject.csproj
└── tests/
└── MyProject.Tests/
├── CalculatorTests.cs
└── MyProject.Tests.csproj
```text
```xml
<Project Sdk=>
<PropertyGroup>
<TargetFramework>net9</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable></IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include= Version=>
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include= Version= />
<PackageReference Include= Version= />
<PackageReference Include= Version=>
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Using Include= />
</ItemGroup>
<ItemGroup>
<ProjectReference Include= />
</ItemGroup>
</Project>
```text
| Assertion Method | Purpose |
| ----------------------------------- | ---------------- |
| `Assert.Equal(expected, actual)` | Verify equality |
| `Assert.NotEqual(expected, actual)` | Verify inequality |
| `Assert.True(condition)` | Verify condition |
| `Assert.False(condition)` | Verify condition |
| `Assert.Null()` | Verify |
| `Assert.NotNull()` | Verify |
| `Assert.Throws<T>(action)` | Verify throws specific exception |
| `Assert.Empty(collection)` | Verify collection empty |
| `Assert.Contains(item, collection)` | Verify collection contains item |
When generating tests a method, ensure coverage of:
- [ ] **Happy Path** - Standard input produces expected output
- [ ] **Boundary Conditions** - Minimum, maximum values, zero, empty strings
- [ ] **Invalid Input** - , negative numbers, wrong formats
- [ ] **Exception Cases** - Scenarios expected to exceptions
This skill content extracted series:
- **Day - Old School Engineer