C# FakeItEasy
上次修改时间:2023 年 9 月 2 日
在本文中,我们将展示如何使用 FakeItEasy 库在 C# 中进行模拟。
模拟 (Faking) 是用伪造对象 (fakes) 或测试替身 (test doubles) 替换外部依赖项。 这些类或组件在单元测试中模拟成功或失败的操作。
使用伪造对象主要是因为外部依赖项当前可能无法用于测试,或者它们的使用成本非常高。
FakeItEasy 是一个易于使用的 .NET 模拟库。
$ dotnet add package FakeItEasy $ dotnet add package Microsoft.NET.Test.Sdk $ dotnet add package MSTest.TestAdapter $ dotnet add package MSTest.TestFramework
在本文中,我们使用 MSTest 测试框架。
C# FakeItEasy 简单示例
在第一个示例中,我们用伪造对象替换一个简单的 HelloService
类。
namespace Messages.Services; public interface IMessageService { string GetHelloMessage(); string GetGreetingMessage(); }
FakeItEasy 从 IMessageService
接口创建伪造对象。
namespace Messages.Services; public class MessageService : IMessageService { public string GetHelloMessage() { return "Hello there!"; } public string GetGreetingMessage() { return "Good Morning!"; } }
MessageService
是 IMessageService
的实现。
namespace Messages.Tests; using Microsoft.VisualStudio.TestTools.UnitTesting; using FakeItEasy; using Messages.Services; [TestClass] public class MessageServiceTest { private const string Expected1 = "Hello there!"; private const string Expected2 = "Good Morning!"; [TestMethod] public void HelloMessageTest() { var msgService = A.Fake<IMessageService>(); A.CallTo(() => msgService.GetHelloMessage()).Returns(Expected1); var res = msgService.GetHelloMessage(); Assert.AreEqual(Expected1, res); } [TestMethod] public void GreetingMessageTest() { var msgService = A.Fake<IMessageService>(); A.CallTo(() => msgService.GetGreetingMessage()).Returns(Expected2); var res = msgService.GetGreetingMessage(); Assert.AreEqual(Expected2, res); } }
在 MessageServiceTest
中,我们测试 MessageService
类。
var msgService = A.Fake<IMessageService>(); A.CallTo(() => msgService.GetHelloMessage()).Returns(Expected1);
我们从 IMessageService
接口创建一个伪造的 MessageService
,并为 GetHelloMessage
调用定义一个响应。
var res = msgService.GetHelloMessage(); Assert.AreEqual(Expected1, res);
该方法使用伪造对象而不是实际类进行测试。
C# FakeItEasy 示例 II
由于我们有一个带有测试框架的控制台程序,我们需要将以下选项添加到项目文件中。
<GenerateProgramFile>false</GenerateProgramFile>
否则,我们将有两个主要的入口点发生冲突。
$ dotnet add package Bogus
除了前面提到的包之外,我们还添加了 Bogus 库来创建伪造数据。
namespace Users.Models; public class User { public User(string fname, string lname, string occupation) => (FirstName, LastName, Occupation) = (fname, lname, occupation); public string FirstName { get; set; } public string LastName { get; set; } public string Occupation { get; set; } public override string ToString() => $"{FirstName} {LastName} is a {Occupation}"; }
这是 User
类。
namespace Users.Services; using Users.Models; public interface IUserService { User GetUser(); IList<User> GetUsers(int n); }
我们有一个 IUserService
接口,其中包含两个合约方法。 GetUser
返回单个用户,GetUsers
返回 n 个用户。
namespace Users.Services; using Users.Models; using Bogus; public class UserService : IUserService { private List<string> occupations = new List<string> { "teacher", "programmer", "driver", "accountant" }; public IList<User> GetUsers(int n) { var users = new List<User>(); foreach (int value in Enumerable.Range(1, n)) { users.Add(CreateUser()); } return users; } public User GetUser() { var user = CreateUser(); return user; } public User CreateUser() { var faker = new Faker(); var fname = faker.Person.FirstName; var lname = faker.Person.LastName; int n = occupations.Count(); int millis = DateTime.Now.Millisecond; var occupation = occupations.ElementAt(new Random(millis).Next(n)); return new User(fname, lname, occupation); } }
我们的 UserService
实现了合约方法。 它使用 Bogus 为用户生成伪造数据。
namespace Main; using Users.Services; public class Program { public static void Main(string[] args) { var userService = new UserService(); var u1 = userService.GetUser(); Console.WriteLine(u1); var users = userService.GetUsers(5); Console.WriteLine(string.Join("\n", users)); } }
这是使用 userService
的主控制台程序。
namespace UserService.Tests; using Microsoft.VisualStudio.TestTools.UnitTesting; using FakeItEasy; using Users.Services; using Users.Models; [TestClass] public class MessageTest { [TestMethod] public void GetUserTest() { var userService = A.Fake<IUserService>(); var dummyUser = A.Dummy<User>(); A.CallTo(() => userService.GetUser()).Returns(dummyUser); var res = userService.GetUser(); Assert.AreEqual(dummyUser, res); } [TestMethod] [DataRow(2)] [DataRow(5)] [DataRow(10)] public void GetUsersTest(int n) { var userService = A.Fake<IUserService>(); var dummyUsers = A.CollectionOfFake<User>(n); A.CallTo(() => userService.GetUsers(n)).Returns(dummyUsers); var res = userService.GetUsers(n); Assert.AreEqual(dummyUsers, res); } }
我们使用测试替身测试 UserService
类。
var userService = A.Fake<IUserService>();
首先,我们创建一个伪造的 UserService
。
var dummyUser = A.Dummy<User>(); A.CallTo(() => userService.GetUser()).Returns(dummyUser);
然后我们定义一个虚拟用户,并将其设置为 GetUser
方法调用的响应。
var res = userService.GetUser(); Assert.AreEqual(dummyUser, res);
最后,我们使用测试替身测试 GetUser
方法。
[TestMethod] [DataRow(2)] [DataRow(5)] [DataRow(10)] public void GetUsersTest(int n) { var userService = A.Fake<IUserService>(); var dummyUsers = A.CollectionOfFake<User>(n); A.CallTo(() => userService.GetUsers(n)).Returns(dummyUsers); var res = userService.GetUsers(n); Assert.AreEqual(dummyUsers, res); }
使用 MSTest 的 DataRow
,我们依次使用值 2、5 和 10 运行 GetUsers
方法。
来源
在本文中,我们已经用 C# 中的 FakeItEasy 将两个实际类替换为测试替身。
作者
列出所有 C# 教程。