如何为建造者模式编写XUnit单元测试?含IDatabase模拟方案
针对UserBuilder的XUnit单元测试方案
1. 模拟第三方IDatabase接口
用Moq框架创建IDatabase的模拟实例,无需依赖真实数据库。先安装Moq NuGet包。
2. 测试SetName方法
推荐方案:调整User类暴露Name属性
如果有权限修改User类,把私有name字段改为公共属性,这样测试更简洁且符合设计原则:
public class User { public string Name { get; set; } public IDataBase db { get; set; } // 其他成员 }
测试代码:
public class UserBuilderTest { [Fact] public void SetName_ConvertsInputToLowercase() { // Arrange var mockDb = new Mock<IDataBase>(); var builder = new UserBuilder(mockDb.Object); var expected = "john"; // Act builder.SetName("John"); // 模拟数据库不存在该名称,确保Build能通过验证 mockDb.Setup(db => db.contains(expected)).Returns(false); var user = builder.Build(); // Assert Assert.Equal(expected, user.Name); } }
备选方案:用反射访问私有字段(无法修改User类时)
如果不能改动User类,通过反射读取私有字段:
[Fact] public void SetName_ConvertsInputToLowercase_WithReflection() { // Arrange var mockDb = new Mock<IDataBase>(); var builder = new UserBuilder(mockDb.Object); var expected = "john"; // Act builder.SetName("John"); // 反射获取UserBuilder的私有_user字段 var userField = typeof(UserBuilder).GetField("_user", BindingFlags.NonPublic | BindingFlags.Instance); var user = (User)userField.GetValue(builder); // 反射获取User的私有name字段 var nameField = typeof(User).GetField("name", BindingFlags.NonPublic | BindingFlags.Instance); var actual = (string)nameField.GetValue(user); // Assert Assert.Equal(expected, actual); }
3. 测试Validate方法
模拟IDatabase的contains方法,验证不同场景下的异常抛出逻辑:
[Fact] public void Validate_ThrowsException_WhenNameIsNull() { var mockDb = new Mock<IDataBase>(); var builder = new UserBuilder(mockDb.Object); Assert.Throws<InvalidDataException>(() => builder.Validate()); } [Fact] public void Validate_ThrowsException_WhenNameExistsInDatabase() { var testName = "john"; var mockDb = new Mock<IDataBase>(); mockDb.Setup(db => db.contains(testName)).Returns(true); var builder = new UserBuilder(mockDb.Object); builder.SetName(testName); Assert.Throws<InvalidDataException>(() => builder.Validate()); } [Fact] public void Validate_Passes_WhenNameIsValid() { var testName = "john"; var mockDb = new Mock<IDataBase>(); mockDb.Setup(db => db.contains(testName)).Returns(false); var builder = new UserBuilder(mockDb.Object); builder.SetName(testName); // 不抛出异常则测试通过 builder.Validate(); }
4. 测试Build方法
验证Validate被调用、persist执行,且返回正确的User对象:
[Fact] public void Build_ReturnsValidUser_AndExecutesPersist() { var testName = "john"; var mockDb = new Mock<IDataBase>(); mockDb.Setup(db => db.contains(testName)).Returns(false); var builder = new UserBuilder(mockDb.Object); builder.SetName(testName); var user = builder.Build(); Assert.Equal(testName, user.Name); // 假设已暴露Name属性 mockDb.Verify(db => db.persist(), Times.Once); // 验证persist被调用一次 }
内容的提问来源于stack exchange,提问作者Selva
相关产品推荐
相关产品推荐

