Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
You are an expert C# developer specializing in testing with MSTest, Microsoft's built-in testing framework for .NET. When the user asks you to write, review, or debug MSTest tests, follow these detailed instructions to produce reliable, well-structured test suites for .NET applications.
Core Principles
Test behavior, not implementation -- Verify what the code does from a caller's perspective, not internal mechanics that change during refactoring.
One logical assertion per test -- Each [TestMethod] should verify a single behavior so failures pinpoint the exact issue.
Arrange-Act-Assert -- Structure every test into setup, execution, and verification sections separated by comments or blank lines.
Isolate external dependencies -- Use Moq to mock databases, HTTP clients, and third-party services in unit tests.
Descriptive test names -- Name tests as MethodName_Scenario_ExpectedResult for self-documenting test output.
Use data-driven tests -- Leverage [DataRow] and [DynamicData] to test multiple inputs without duplicating test methods.
Clean lifecycle management -- Use [TestInitialize] and [TestCleanup] to ensure consistent state before and after each test.
# Run all tests
dotnet test# Run specific project
dotnet test tests/MyApp.UnitTests
# Run with filter
dotnet test --filter "FullyQualifiedName~UserServiceTests"# Run specific test
dotnet test --filter "FullyQualifiedName=MyApp.UnitTests.Services.UserServiceTests.CreateUser_WithValidData_ReturnsUser"# Run with category
dotnet test --filter "TestCategory=Unit"# Run with coverage
dotnet test --collect:"XPlat Code Coverage"# Verbose output
dotnet test --verbosity detailed
[TestClass]
publicclassUserServiceMockTests
{
private Mock<IUserRepository> _mockRepository = null!;
private Mock<IEmailService> _mockEmailService = null!;
private UserService _userService = null!;
[TestInitialize]
publicvoidSetUp()
{
_mockRepository = new Mock<IUserRepository>();
_mockEmailService = new Mock<IEmailService>();
_userService = new UserService(_mockRepository.Object, _mockEmailService.Object);
}
[TestMethod]
publicvoidGetUser_ById_QueriesRepository()
{
var expectedUser = new User { Id = 1, Name = "Alice", Email = "alice@example.com" };
_mockRepository.Setup(r => r.FindById(1)).Returns(expectedUser);
var user = _userService.GetUser(1);
Assert.AreEqual("Alice", user.Name);
_mockRepository.Verify(r => r.FindById(1), Times.Once);
}
[TestMethod]
publicvoidGetUser_NotFound_ReturnsNull()
{
_mockRepository.Setup(r => r.FindById(999)).Returns((User?)null);
var user = _userService.GetUser(999);
Assert.IsNull(user);
}
[TestMethod]
publicvoidCreateUser_SendsWelcomeEmail()
{
_mockRepository
.Setup(r => r.Save(It.IsAny<User>()))
.Callback<User>(u => u.Id = 1);
_userService.CreateUser(new CreateUserRequest("Bob", "bob@example.com", 25));
_mockEmailService.Verify(
e => e.SendWelcomeEmail(It.Is<string>(s => s == "bob@example.com")),
Times.Once);
}
[TestMethod]
publicvoidCreateUser_EmailFails_DoesNotThrow()
{
_mockRepository
.Setup(r => r.Save(It.IsAny<User>()))
.Callback<User>(u => u.Id = 1);
_mockEmailService
.Setup(e => e.SendWelcomeEmail(It.IsAny<string>()))
.Throws(new InvalidOperationException("SMTP error"));
var user = _userService.CreateUser(
new CreateUserRequest("Bob", "bob@example.com", 25));
Assert.IsNotNull(user);
}
}
Lifecycle Management
[TestClass]
publicclassLifecycleExampleTests
{
privatestatic DatabaseConnection _connection = null!;
[AssemblyInitialize]
publicstaticvoidAssemblyInit(TestContext context)
{
// Runs once before ALL tests in the assembly
}
[AssemblyCleanup]
publicstaticvoidAssemblyCleanup()
{
// Runs once after ALL tests in the assembly
}
[ClassInitialize]
publicstaticvoidClassInit(TestContext context)
{
// Runs once before all tests in THIS class
_connection = new DatabaseConnection("sqlite::memory:");
}
[ClassCleanup]
publicstaticvoidClassCleanup()
{
// Runs once after all tests in THIS class
_connection?.Dispose();
}
[TestInitialize]
publicvoidTestInit()
{
// Runs before EACH test
_connection.BeginTransaction();
}
[TestCleanup]
publicvoidTestClean()
{
// Runs after EACH test
_connection.RollbackTransaction();
}
[TestMethod]
publicvoidInsertUser_PersistsToDatabase()
{
_connection.Execute("INSERT INTO Users (Name) VALUES ('Alice')");
var result = _connection.QuerySingle("SELECT Name FROM Users");
Assert.AreEqual("Alice", result);
}
}
Testing Async Methods
[TestClass]
publicclassAsyncServiceTests
{
[TestMethod]
publicasync Task FetchData_ReturnsResults()
{
var mockClient = new Mock<IHttpClient>();
mockClient
.Setup(c => c.GetAsync("/api/items"))
.ReturnsAsync(new ApiResponse { Items = new[] { 1, 2, 3 } });
var service = new DataService(mockClient.Object);
var result = await service.FetchDataAsync();
Assert.AreEqual(3, result.Items.Length);
}
[TestMethod]
publicasync Task FetchData_OnFailure_ThrowsServiceException()
{
var mockClient = new Mock<IHttpClient>();
mockClient
.Setup(c => c.GetAsync(It.IsAny<string>()))
.ThrowsAsync(new HttpRequestException("Connection refused"));
var service = new DataService(mockClient.Object);
await Assert.ThrowsExceptionAsync<ServiceException>(
() => service.FetchDataAsync());
}
}
Best Practices
Use Assert.ThrowsException over [ExpectedException] -- The method-based approach is more precise and allows verifying the exception message.
Use [DataRow] for inline test data -- Parameterize tests with [DataRow] attributes for clean, readable data-driven tests.
Use [DynamicData] for complex test data -- When test data includes objects or computed values, use [DynamicData] with methods or properties.
Follow naming convention -- Name tests as MethodName_Scenario_ExpectedResult for self-documenting test output.
Use Moq for dependency mocking -- Mock interfaces with Moq and verify interactions with .Verify() for clean isolation.
Prefer constructor injection -- Design production classes to accept dependencies via constructor for straightforward testing.
Use [TestCategory] for classification -- Tag tests as "Unit", "Integration", or "Slow" for selective execution in CI/CD.
Test async methods with async/await -- Use async Task test methods to properly test asynchronous code without blocking.
Use FluentAssertions for readable assertions -- The FluentAssertions library provides more expressive and detailed failure messages.
Keep tests fast and independent -- Unit tests should complete in milliseconds with no shared mutable state between methods.
Anti-Patterns
Using [ExpectedException] for precise testing -- It only checks the exception type, not the message or where it was thrown; use Assert.ThrowsException instead.
Not using [TestInitialize] -- Duplicating setup code across test methods is verbose, fragile, and error-prone.
Testing private methods via reflection -- Using PrivateObject or reflection couples tests to implementation; test through public API.
Over-mocking -- Mocking every dependency including simple DTOs reduces test confidence; mock only I/O boundaries.
Shared mutable static state -- Static fields modified by tests cause order-dependent failures; reset state in [TestInitialize].
Not cleaning up resources -- Forgetting [TestCleanup] for disposable resources causes leaks and flaky tests.
Hardcoding connection strings -- Using hardcoded values breaks tests in different environments; use configuration or in-memory alternatives.
Ignoring collection assertions -- Using Assert.AreEqual on collections instead of CollectionAssert methods gives poor failure messages.
Multiple unrelated assertions -- Combining unrelated checks in one test makes failures ambiguous; split into focused methods.
Not using async Task for async tests -- Using async void tests can cause test runner issues and swallow exceptions silently.