Skip to content
AI & Agents
Skill

/csharp-mstest

Get best practices for MSTest 3.x/4.x unit testing, including modern assertion APIs and data-driven tests

From plugin
awesome-copilot
41k200 skills200 agents

Claude Code

$ npx -y skills add github/awesome-copilot --skill csharp-mstest --agent claude-code

SKILL.md

csharp-mstest.SKILL.md
name: csharp-mstest
description: 'Get best practices for MSTest 3.x/4.x unit testing, including modern assertion APIs and data-driven tests'

MSTest Best Practices (MSTest 3.x/4.x)

Your goal is to help me write effective unit tests with modern MSTest, using current APIs and best practices.

Project Setup

  • Use a separate test project with naming convention `[ProjectName].Tests`
  • Reference MSTest 3.x+ NuGet packages (includes analyzers)
  • Consider using MSTest.Sdk for simplified project setup
  • Run tests with `dotnet test`

Test Class Structure

  • Use `[TestClass]` attribute for test classes
  • **Seal test classes by default** for performance and design clarity
  • Use `[TestMethod]` for test methods (prefer over `[DataTestMethod]`)
  • Follow Arrange-Act-Assert (AAA) pattern
  • Name tests using pattern `MethodName_Scenario_ExpectedBehavior`
[TestClass]
public sealed class CalculatorTests
{
    [TestMethod]
    public void Add_TwoPositiveNumbers_ReturnsSum()
    {
        // Arrange
        var calculator = new Calculator();

        // Act
        var result = calculator.Add(2, 3);

        // Assert
        Assert.AreEqual(5, result);
    }
}

Test Lifecycle

  • **Prefer constructors over `[TestInitialize]`** - enables `readonly` fields and follows standard C# patterns
  • Use `[TestCleanup]` for cleanup that must run even if test fails
  • Combine constructor with async `[TestInitialize]` when async setup is needed
[TestClass]
public sealed class ServiceTests
{
    private readonly MyService _service;  // readonly enabled by constructor

    public ServiceTests()
    {
        _service = new MyService();
    }

    [TestInitialize]
    public async Task InitAsync()
    {
        // Use for async initialization only
        await _service.WarmupAsync();
    }

    [TestCleanup]
    public void Cleanup() => _service.Reset();
}

Execution Order

1. **Assembly Initialization** - `[AssemblyInitialize]` (once per test assembly) 2. **Class Initialization** - `[ClassInitialize]` (once per test class) 3. **Test Initialization** (for every test method): 1. Constructor 2. Set `TestContext` property 3. `[TestInitialize]` 4. **Test Execution** - test method runs 5. **Test Cleanup** (for every test method): 1. `[TestCleanup]` 2. `DisposeAsync` (if implemented) 3. `Dispose` (if implemented) 6. **Class Cleanup** - `[ClassCleanup]` (once per test class) 7. **Assembly Cleanup** - `[AssemblyCleanup]` (once per test assembly)

Modern Assertion APIs

MSTest provides three assertion classes: `Assert`, `StringAssert`, and `CollectionAssert`.

Assert Class - Core Assertions

// Equality
Assert.AreEqual(expected, actual);
Assert.AreNotEqual(notExpected, actual);
Assert.AreSame(expectedObject, actualObject);      // Reference equality
Assert.AreNotSame(notExpectedObject, actualObject);

// Null checks
Assert.IsNull(value);
Assert.IsNotNull(value);

// Boolean
Assert.IsTrue(condition);
Assert.IsFalse(condition);

// Fail/Inconclusive
Assert.Fail("Test failed due to...");
Assert.Inconclusive("Test cannot be completed because...");

Exception Testing (Prefer over `[ExpectedException]`)

// Assert.Throws - matches TException or derived types
var ex = Assert.Throws<ArgumentException>(() => Method(null));
Assert.AreEqual("Value cannot be null.", ex.Message);

// Assert.ThrowsExactly - matches exact type only
var ex = Assert.ThrowsExactly<InvalidOperationException>(() => Method());

// Async versions
var ex = await Assert.ThrowsAsync<HttpRequestException>(async () => await client.GetAsync(url));
var ex = await Assert.ThrowsExactlyAsync<InvalidOperationException>(async () => await Method());

Collection Assertions (Assert class)

Assert.Contains(expectedItem, collection);
Assert.DoesNotContain(unexpectedItem, collection);
Assert.ContainsSingle(collection);  // exactly one element
Assert.HasCount(5, collection);
Assert.IsEmpty(collection);
Assert.IsNotEmpty(collection);

String Assertions (Assert class)

Assert.Contains("expected", actualString);
Assert.StartsWith("prefix", actualString);
Assert.EndsWith("suffix", actualString);
Assert.DoesNotStartWith("prefix", actualString);
Assert.DoesNotEndWith("suffix", actualString);
Assert.MatchesRegex(@"\d{3}-\d{4}", phoneNumber);
Assert.DoesNotMatchRegex(@"\d+", textOnly);

Comparison Assertions

Assert.IsGreaterThan(lowerBound, actual);
Assert.IsGreaterThanOrEqualTo(lowerBound, actual);
Assert.IsLessThan(upperBound, actual);
Assert.IsLessThanOrEqualTo(upperBound, actual);
Assert.IsInRange(actual, low, high);
Assert.IsPositive(number);
Assert.IsNegative(number);

Type Assertions

// MSTest 3.x - uses out parameter
Assert.IsInstanceOfType<MyClass>(obj, out var typed);
typed.DoSomething();

// MSTest 4.x - returns typed result directly
var typed = Assert.IsInstanceOfType<MyClass>(obj);
typed.DoSomething();

Assert.IsNotInstanceOfType<WrongType>(obj);

Assert.That (MSTest 4.0+)

Assert.That(result.Count > 0);  // Auto-captures expression in failure message

StringAssert Class

> **Note:** Prefer `Assert` class equivalents when available (e.g., `Assert.Contains("expected", actual)` over `StringAssert.Contains(actual, "expected")`).

StringAssert.Contains(actualString, "expected");
StringAssert.StartsWith(actualString, "prefix");
StringAssert.EndsWith(actualString, "suffix");
StringAssert.Matches(actualString, new Regex(@"\d{3}-\d{4}"));
StringAssert.DoesNotMatch(actualString, new Regex(@"\d+"));

CollectionAssert Class

> **Note:** Prefer `Assert` class equivalents when available (e.g., `Assert.Contains`).

// Containment
CollectionAssert.Contains(collection, expectedItem);
CollectionAssert.DoesNotContain(collection, unexpectedItem);

// Equality (same elements, same order)
CollectionAssert.AreEqual(expectedCollection, actualCollection);
CollectionAssert.AreNotE
Read more
@github
Ships withawesome-copilot

A community-created collection of custom agents, instructions, skills, hooks, workflows, and plugins to supercharge your GitHub Copilot experience.

41k200 skills200 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
40.7k
Star history of github/awesome-copilot on GitHub, a chart by star-history.com

Other skills on awesome-copilot.

acreadiness-assess

acreadiness-assess

Run the AgentRC readiness assessment on the current repository and produce a static HTML dashboard at reports/index.html. Wraps…

More skills from other plugins.

1password

1password

Set up and use 1Password CLI for sign-in, desktop integration, and reading or injecting secrets.

openclaw2w393k
@openclaw@openclawInstall Skill

Questions about csharp-mstest.

Which coding agents can use csharp-mstest?
csharp-mstest installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.