基于上一次的单元测试-xUnit进行
Models文件夹
Staff类修改为:
public class Staff { public int Id { get; set; } public string Name { get; set; } public string State { get; set; } public int Age { get; set; } } |
创建一个IRepository接口
public interface IRepository { IEnumerable<Staff> Staffs{ get; } } |
创建一个SimpleRepository类实现IRepository接口
public class SimpleRepository : IRepository { public IEnumerable<Staff> Staffs=> new Staff[] { new Staff(){ Id = 1, Name = "张三", State = "在职", Age = 18 }, new Staff(){ Id = 2, Name = "李四", State = "离职", Age = 20 }, new Staff(){ Id = 10, Name = "王五", State = "在职", Age = 36 }, new Staff(){ Id = 8, Name = "血友病", State = "在职", Age = 18 } }; } |
这样的好处:
- 实体类更加直观
- 假设SimpleRepository类里的数据是Sql的数据,我们测试时定义假数据实现接口,因为接口是一种规范并且可以进行里氏转换
Controllers文件夹
HomeController 内容修改为
public class HomeController : Controller { private IRepository repository = new SimpleRepository();
public IRepository Repository { get => repository ; set => repository = value; }
public IActionResult Index() { return View(Repository.Staffs.Where(x => x.State == "在职")); } } |
Staffitems.Tests项目
在NuGet管理器种添加Moq软件包
Moq是什么? ==== 是一个用于在应用程序种创建组件的仿冒实现的软件包
Moq有何用? ====Moq框架是的为单元测试创建仿冒组件以隔离应用程序的部件变得更容易
有什么替代品? ===== 有很多替代品,包括NSubstitue和FakeItEasy。所有这些框架都提供类似的功能,可在它们之间进行选择
在HomeControllerTests类中使用Moq
红色部分为新增或者修改
绿色部分为解释
public class HomeControllerTests { [Fact] public void IndexActionModelIsComplete2() { //创建Mocking var mock = new Mock<IRepository>();
//SetupGet:为调用属性getter指定假数据的设置。 //当Products被读取时返回Returns方法里的结果 mock.SetupGet(x => x.Staffs).Returns(new[] { new Staff{ Name ="z1",Age = 5, State = "在职" }, new Staff{ Name ="z2",Age = -3232 ,State = "在职" }, new Staff{ Name ="z3",Age = 99999 ,State = "在职" } });
//获取Home控制器,并重新设置该Repository的值 //Repository一开始指向与SimpleRepository //现在指向与我们在上面定义的假数据 var controll = new HomeController() { Repository = mock.Object };
//调用HomeControll中的Index()方法并获取返回的类型 var model = (controll.Index() as ViewResult).ViewData.Model as IEnumerable<Staff>;
//对比预料值与实际值是否一致 Assert.Equal( controll.Repository.Staffs.Where(x => x.State == "在职"), model, Comparer.Get<Staff>((a, b) => a.Name == b.Name && a.State == b.State && a.Id == b.Id) ); } } |
测试Index()方法只执行了一次
[Fact] public void IndexActionModelIsComplete3() { var controller = new HomeController(); var mock = new Mock<IRepository>();
mock.SetupGet(m => m.Staffs).Returns(new[] { new Staff{ Name ="z1",Age = 5, State = "在职" }, new Staff{ Name ="z2",Age = -3232 ,State = "在职" }, new Staff{ Name ="z3",Age = 99999 ,State = "在职" } });
controller.Repository = mock.Object;
//执行Index()方法 var result = controller.Index(); var result2 = controller.Index(); var result3 = controller.Index();
//验证是否在模拟上读取了Products属性。并且只读取了一次(Times.Once) mock.VerifyGet(m => m.Staffs, Times.Once); } |
删除以下代码就行了
var result2 = controller.Index(); var result3 = controller.Index(); |