[Fact]
Learn to write test methods with [Fact].
The [Fact] attribute
[Fact] declares that a method is a test. It takes no parameters and returns nothing; it checks a single scenario. The runner collects all methods marked this way and runs them in turn.
A good [Fact] test focuses on one behavior: one input, one expected result. If it checks multiple things, a failure leaves the broken piece unclear. So TestAddReturnsFive and TestAddNegative are separate methods.
Test naming and structure
Test names should describe behavior: TestAddReturnsFive, ShouldThrowOnNegative, or Add_TwoPlusThree_ReturnsFive. These names reveal the failure at a glance.
Each test must be independent: no test should depend on another's data or order. That is why tests share setup in a Setup method (in xUnit, the constructor); each test starts with its own instance.
Exercise Write two [Fact] tests
Define FactAttribute and a static Assert class (Assert.Equal<T> throws Exception on inequality). Add both Add(int, int) and Subtract(int, int) to Calculator. Write two [Fact] methods in CalculatorTests: TestAddReturnsFive calls Assert.Equal(5, Calculator.Add(2, 3)); TestSubtractReturnsOne calls Assert.Equal(1, Calculator.Subtract(3, 2)). In Main, call both and print "Test passed: Add and Subtract" on success.
Show example solution
Attribute { } and static class Assert { public static void Equal<T>(T expected, T actual) { if (!EqualityComparer<T>.Default.Equals(expected, actual)) throw new Exception($"Expected {expected}"); } }. Write class Calculator { public static int Add(int a, int b) => a + b; public static int Subtract(int a, int b) => a - b; }. Write class CalculatorTests { [Fact] public void TestAddReturnsFive() { Assert.Equal(5, Calculator.Add(2, 3)); } [Fact] public void TestSubtractReturnsOne() { Assert.Equal(1, Calculator.Subtract(3, 2)); } }. In Main: var t = new CalculatorTests(); t.TestAddReturnsFive(); t.TestSubtractReturnsOne(); Console.WriteLine("Test passed: Add and Subtract");
Example solution:
using System;
class FactAttribute : Attribute { }
static class Assert
{
public static void Equal<T>(T expected, T actual)
{
if (!EqualityComparer<T>.Default.Equals(expected, actual))
throw new Exception($"Expected {expected}, got {actual}");
}
}
class Calculator
{
public static int Add(int a, int b) => a + b;
public static int Subtract(int a, int b) => a - b;
}
class CalculatorTests
{
[Fact]
public void TestAddReturnsFive()
{
Assert.Equal(5, Calculator.Add(2, 3));
}
[Fact]
public void TestSubtractReturnsOne()
{
Assert.Equal(1, Calculator.Subtract(3, 2));
}
}
class Program
{
static void Main()
{
var tests = new CalculatorTests();
tests.TestAddReturnsFive();
tests.TestSubtractReturnsOne();
Console.WriteLine("Test passed: Add and Subtract");
}
}
Test yourself
-
Which methods does [Fact] mark?
- Only static methods
- Parameterless void test methods
- Async methods only
- Only private methods
Show answer
Parameterless void test methods — Correct. [Fact] marks parameterless void test methods.
-
Complete the test method
public void ____() { Assert.Equal(4, Calculator.Add(2, 2)); }Show answer
public void TestAddTwoPlusTwo() { Assert.Equal(4, Calculator.Add(2, 2)); } -
What should a [Fact] method do?
- Test multiple classes at once
- Write to a database
- Read user input
- Test a single behavior
Show answer
Test a single behavior — Correct. [Fact] tests one behavior; it does not mix concerns.