返回 Skill 列表
extension
分类: 开发与工程无需 API Key

nunit

NUnit测试框架,包含TestCase、SetUp/TearDown、断言以及针对.NET应用程序的参数化测试。使用时机:用户提到“NUnit”、“TestCase”、“TestFixture”、“NUnit断言”、“NUnit参数化测试”或“.NET NUnit”。不适用于:xUnit - 请使用`xunit`,MSTest,JavaScript测试框架。

person作者: jakexiaohubgithub

NUnit - Quick Reference

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: xunit for .NET testing patterns (concepts transfer).

Basic Test Structure

[TestFixture]
public class UserServiceTests
{
    private Mock<IUserRepository> _repository = null!;
    private UserService _service = null!;

    [SetUp]
    public void SetUp()
    {
        _repository = new Mock<IUserRepository>();
        _service = new UserService(_repository.Object, Mock.Of<ILogger<UserService>>());
    }

    [Test]
    public async Task GetById_ExistingUser_ReturnsUser()
    {
        _repository.Setup(r => r.GetByIdAsync(1))
            .ReturnsAsync(new User { Id = 1, Name = "Alice" });

        var result = await _service.GetByIdAsync(1);

        Assert.That(result, Is.Not.Null);
        Assert.That(result!.Name, Is.EqualTo("Alice"));
    }

    [Test]
    public async Task GetById_NonExisting_ReturnsNull()
    {
        _repository.Setup(r => r.GetByIdAsync(999)).ReturnsAsync((User?)null);

        var result = await _service.GetByIdAsync(999);

        Assert.That(result, Is.Null);
    }
}

Parameterized Tests

[TestCase("", false)]
[TestCase("a", false)]
[TestCase("ab", true)]
[TestCase("valid name", true)]
public void IsValidName_ReturnsExpected(string name, bool expected)
{
    var result = _validator.IsValidName(name);
    Assert.That(result, Is.EqualTo(expected));
}

[TestCaseSource(nameof(GetTestData))]
public void Calculate_ReturnsExpected(int a, int b, int expected)
{
    Assert.That(_calculator.Add(a, b), Is.EqualTo(expected));
}

private static IEnumerable<TestCaseData> GetTestData()
{
    yield return new TestCaseData(1, 2, 3).SetName("Positive numbers");
    yield return new TestCaseData(-1, 1, 0).SetName("Mixed signs");
    yield return new TestCaseData(0, 0, 0).SetName("Zeros");
}

Constraint-Based Assertions

// Equality
Assert.That(result, Is.EqualTo(42));
Assert.That(name, Is.EqualTo("alice").IgnoreCase);

// Comparison
Assert.That(age, Is.GreaterThan(0).And.LessThan(150));
Assert.That(price, Is.InRange(0m, 1000m));

// Collections
Assert.That(users, Has.Count.EqualTo(3));
Assert.That(users, Has.Exactly(1).Matches<User>(u => u.Name == "Alice"));
Assert.That(names, Is.Ordered.Ascending);
Assert.That(items, Does.Contain("expected"));

// Exceptions
Assert.ThrowsAsync<NotFoundException>(async () => await _service.GetByIdAsync(999));
Assert.That(async () => await _service.CreateAsync(null!), Throws.ArgumentNullException);

// String
Assert.That(message, Does.StartWith("Error").And.Contains("not found"));

SetUp and TearDown

[TestFixture]
public class IntegrationTests
{
    [OneTimeSetUp]  // Runs once before all tests
    public async Task OneTimeSetUp() { /* DB setup */ }

    [SetUp]  // Runs before each test
    public void SetUp() { /* Reset state */ }

    [TearDown]  // Runs after each test
    public void TearDown() { /* Cleanup */ }

    [OneTimeTearDown]  // Runs once after all tests
    public async Task OneTimeTearDown() { /* DB teardown */ }
}

Anti-Patterns

| Anti-Pattern | Why It's Bad | Correct Approach | |--------------|--------------|------------------| | Classic Assert.AreEqual | Less readable | Use constraint model Assert.That | | Shared state between tests | Flaky tests | Reset in [SetUp] | | [Test] on async void | Exceptions lost | Use async Task return type | | Too many asserts per test | Hard to identify failure | One logical assertion per test |

Quick Troubleshooting

| Issue | Likely Cause | Solution | |-------|--------------|----------| | Test not discovered | Missing [Test] or [TestFixture] | Add required attributes | | SetUp not running | Wrong attribute | Use [SetUp] not [Setup] | | Async test ignored | Missing async Task | Change return type from void | | TestCaseSource fails | Method not static | Make source method static |