🎯 Purpose

You are a principal engineer drafting an internal engineering standards document for a U.S.-based enterprise .NET team. The audience is composed of experienced and senior C# developers who are new to unit testing. The company builds software for credit unions and banking clients, where reliability, maintainability, and clarity are paramount.

This document introduces what, why, when, and how of unit testing only—integration, mutation, UI, or performance testing are out of scope.

Write in clear, professional American English with a slightly conversational and encouraging tone. Subtle dry humor is acceptable only if professional and unobtrusive. Think "helpful senior dev over coffee," not "corporate slideshow."

⸻

📄 Output Format Requirements
	•	Format as Word-import-friendly Markdown.
	•	Use:
	•	## for top-level headings
	•	### for subheadings
	•	Fenced csharp code blocks for all C# code
	•	Tables are allowed where helpful.
	•	Every C# code sample must:
	•	Compile under .NET 8
	•	Use the latest stable versions of:
	•	xUnit
	•	AutoFixture + AutoMoq
	•	Moq
	•	FluentAssertions
	•	Instantiate all objects via AutoFixture — never use new directly in tests.
	•	Use FluentAssertions for all assertions.

⸻

📚 Document Structure and Content

⸻

0. Introduction
	•	Audience: experienced developers, new to professional unit testing
	•	Scope: Unit testing only (no integration, mutation, UI, or performance testing)
	•	Tech stack: xUnit, AutoFixture, AutoMoq, Moq, FluentAssertions
	•	Goals: fast feedback, safe refactoring, consistent style

⸻

1. What is a Unit Test? Why Do We Write Them?
	•	Define unit testing
	•	Introduce the Test Pyramid (unit at the base)
	•	Explain the FIRST principles:
	•	Fast
	•	Isolated
	•	Repeatable
	•	Self-Validating
	•	Timely
	•	Benefits:
	•	Fast feedback
	•	Safer refactoring
	•	Regression safety net
	•	Better design decisions
	•	Living documentation

⸻

2. When and How We Write Tests
	•	TDD (Red/Green/Refactor) walkthrough: real-world example
	•	Feature Work testing: when adding functionality without strict TDD
	•	Bug-Fix Testing: write a failing test before fixing the bug
	•	Reinforce: all of these create unit tests—small, isolated, focused

⸻

3. Writing Good Unit Tests

For each subsection:
	•	Brief explanation
	•	Good (✅) and Bad (❌) C# examples
	•	Always use AutoFixture for instantiation
	•	Always use FluentAssertions for assertions

Topics:
	•	Use AutoFixture to reduce test boilerplate
	•	Write the smallest passing test
	•	Avoid magic numbers and strings
	•	No logic in tests (no loops, ifs, derived values)
	•	Prefer local helpers over shared setups
	•	One Act per test
	•	Test via public behavior only
	•	Make time and randomness deterministic

⸻

4. Common Pitfalls and How to Avoid Them

Each entry must include:
	•	What it is
	•	Why it’s harmful
	•	How to fix it
	•	Good (✅) and Bad (❌) examples

Pitfalls:
	•	Over-mocking
	•	Verifying internal implementation
	•	async void tests
	•	Loose mocks (ConfigureMembers = true)
	•	Shared state across tests
	•	Non-deterministic time or randomness

⸻

5. Unit Test Project Naming Standard

Each solution must have one centralized Unit Test project, named:

STS.<SolutionName>.Test

Example:
	•	Solution: STS.CoreInterfaceService
	•	Unit Test Project: STS.CoreInterfaceService.Test

All unit tests across all projects (.Web, .Data, etc.) must go into this .Test project.
Do not create multiple .Test projects per solution unless explicitly approved.

⸻

6. Running and Debugging Unit Tests
	•	Visual Studio 2022:
	•	Run All Tests
	•	Debug single test
	•	Code Coverage (built-in)
	•	Visual Studio Code:
	•	dotnet test
	•	dotnet watch test
	•	Coverage Gutters extension
	•	CI Integration:
	•	dotnet test --collect:\"XPlat Code Coverage\"

⸻

7. Example Testing Scenarios

For each example:
	•	Provide a realistic business-relevant case
	•	Use AutoFixture, FluentAssertions, Moq properly
	•	Include Good (✅) and Bad (❌) samples if helpful
	•	Keep examples minimal, clear, FIRST-compliant

Required examples:
	•	Testing for Exceptions
Validate error cases, use .Should().ThrowExactlyAsync<>()
	•	Handling Null or Empty Inputs
Defensive testing for boundary conditions
	•	Testing Boundary Values
Off-by-one, limits, thresholds
	•	Verifying Behavior with Mocks
repoMock.Verify(x => x.Save(...))
	•	Handling Optional Dependencies
Null or stubbed ILogger patterns
	•	Parameterized Testing with [Theory]
Covering multiple input sets cleanly
	•	Testing Time-Based Behavior
Injected IClock/IClockProvider examples
	•	Minimal Multi-Assert Tests
Related assertions for one logical behavior
	•	Asserting Collection Contents
ContainInOrder, Collection Equivalence

⸻

8. A Full Example: TransferService

Provide a full, real-world unit test example:
	•	Using AutoFixture, FluentAssertions, Moq
	•	Inline commentary
	•	Demonstrates FIRST qualities
	•	Clear and practical — not contrived

⸻

9. Further Learning

Bulleted list with links:
	•	xUnit Getting Started
	•	AutoFixture Cheat Sheet
	•	Moq Quickstart
	•	FluentAssertions Introduction
	•	Coverlet Code Coverage
	•	Microsoft Unit Testing Best Practices

⸻

Appendix A: GitHub Copilot Custom Instructions

Explain:
	•	What Copilot custom instructions are
	•	Where they are stored (.github/copilot-instructions.md)
	•	Why they matter for unit testing consistency

Baseline Copilot prompt:

	•	Always use AutoFixture for object creation
	•	Use FluentAssertions for assertions
	•	Follow FIRST testing principles
	•	Avoid async void, over-mocking, shared state, and logic in test bodies
	•	Avoid setting tone, style, or verbosity instructions

⸻

🛡️ Critical Source Integration

Throughout all sections, integrate (not summarize) content from:
	•	Microsoft Unit Testing Best Practices
	•	GitHub Copilot Instructions

If conflicts arise, follow the structure of this document as primary.