481 字
1 分钟
C# 单元测试
环境准备
-
Visual Studio 2026
-
.NET 10
创建解决方案
/UnitTestLearn.sln /UnitTestLearn UnitTestLearn.csproj Program.cs PrimeService.cs CalculateService.cs /UnitTestLearn.Test UnitTestLearn.Test.csproj PrimeTest.cs CalculateTest.csUnitTestLearn 为用于测试的项目,UnitTestLearn.Test 为测试项目。
编写用于单元测试的方法
本次用于单元测试的方法为判断是否为素数和加减乘除运算。
public class PrimeService{ public bool IsPrime(int candidate) { if (candidate == 2) { return true; } if (candidate < 2 || candidate % 2 == 0) { return false; } for(int i = 3; i * i < candidate; i+=2) { if (candidate % i == 0) { return false; } } return true; }}public class CalculateService{ public int Sum(int a, int b) { return a + b; } public int Subtract(int a, int b) { return a - b; } public int Multiply(int a, int b) { return a * b; } public double Divide(double a, double b) { if (b == 0) { throw new DivideByZeroException("除数不能为零"); } return a / b; }}创建单元测试
在 PrimeTest 类中添加如下方法。
public class PrimeTest{ [Theory] [InlineData(-1)] [InlineData(0)] [InlineData(1)] public void IsPrime_InputLessThan2_ReturnsFalse(int value) { var result = new PrimeService().IsPrime(value); Assert.False(result); } [Fact] public void IsPrime_InputIs2_ReturnsTrue() { var primeService = new PrimeService(); bool result = primeService.IsPrime(2); Assert.True(result); }}该 [Fact] 属性声明由测试运行程序运行的测试方法,运行测试后,其将会自动被调用用于测试。该属性通常用于对单个数值进行测试。
而 Assert 用于比较最后的值是否符合要求。
运行测试,可以发现测试全部通过(测试资源管理器可在 测试->测试资源管理器 打开,也可以按 ctrl + E + T 打开),这是因为我们的 IsPrime 方法没有错误。现在将 PrimeService 类下的 IsPrime 方法改为下列代码。再次运行测试,可以发现测试失败,IsPrime_InputIs2_ReturnsTrue 方法测试未通过。
public bool IsPrime(int candidate){ if (candidate == 2) { return false; // 这里把本该返回 true 的地方改为返回 false } if (candidate < 2 || candidate % 2 == 0) { return false; } for(int i = 3; i * i < candidate; i+=2) { if (candidate % i == 0) { return false; } } return true;}而 [Theory] 属性表示执行相同代码但具有不同输入参数的测试套件。可以配合 [InlineData] 属性指定测试样例,如果用这种方式则要在测试方法中设置参数,可以为多个参数,但要一一对应。这种方法指定的测试样例往往结果是相同的,如上面的例子中 -1、0、1 都不是素数,所以共用了一个方法。
在 CalculateTest 中编写如下方法。
public class CalculateTest{ private static int VetifySum(int a, int b) { return a + b; } private static int VetifySubtract(int a, int b) { return a - b; } private static int VetifyMultiply(int a, int b) { return a * b; } private static double VetifyDivide(double a, double b) { if (b == 0) { throw new DivideByZeroException("除数不能为零"); } return a / b; }
[Theory] [InlineData(1, 1)] [InlineData(2, 5)] [InlineData(-912, 1232)] public void Sum_TwoNumbers_ReturnsCorrectResult(int a, int b) { var calculateService = new CalculateService(); // Arrange int expected = VetifySum(a, b); // Act int result = calculateService.Sum(a, b); // Assert Assert.Equal(expected, result); } [Theory] [InlineData(1, 1)] [InlineData(-2, 5)] [InlineData(912, -1232)] public void Subtract_TwoNumbers_ReturnsCorrectResult(int a, int b) { var calculateService = new CalculateService(); // Arrange int expected = VetifySubtract(a, b); // Act int result = calculateService.Subtract(a, b); // Assert Assert.Equal(expected, result); } [Theory] [InlineData(1, 1)] [InlineData(2, 0)] [InlineData(0, 123214)] [InlineData(-9, -12)] [InlineData(9, -12)] [InlineData(31, 7)] public void Multiply_TwoNumbers_ReturnsCorrectResult(int a, int b) { var calculateService = new CalculateService(); // Arrange int expected = VetifyMultiply(a, b); // Act int result = calculateService.Multiply(a, b); // Assert Assert.Equal(expected, result); } [Theory] [InlineData(1, 1)] [InlineData(0,123)] [InlineData(12, 6)] [InlineData(1, 10)] public void Divide_TwoNumbers_ReturnsCorrectResult(double a, double b) { var calculateService = new CalculateService(); // Arrange double expected = VetifyDivide(a, b); // Act double result = calculateService.Divide(a, b); // Assert Assert.Equal(expected, result); }}我们可以用自己的一些方法来辅助进行测试。对于没有属性修饰的方法或者私有方法不会参与测试,可以作为辅助方法在测试方法中对结果进行计算,主要用于自己有”标准答案“的代码时对别人写的代码进行检查。









