.Net单元测试业务实践 (3)

Autofac: Ioc容器

//单元测试部分 public class GetTicketDiscounts_Test { private IXTaDiscountService discountService = null; private IXTaCodeService codeSub = null; public GetTicketDiscounts_Test() { discountService = XTaContainer.Resolve<IXTaDiscountService>(); codeSub = NSubstitute.Substitute.For<IXTaCodeService>(); } } //注册部分 public static class XTaContainer { public readonly static IContainer _container; static XTaContainer() { // Create your builder. var builder = new ContainerBuilder(); //自动注册。 var baseType = typeof(IApplication); var assemblys = AppDomain.CurrentDomain.GetAssemblies().ToList(); builder.RegisterAssemblyTypes(assemblys.ToArray()) .Where(t => baseType.IsAssignableFrom(t) && t != baseType) .AsImplementedInterfaces() .InstancePerLifetimeScope(); //Redis builder.Register(n => Substitute.For<ICache>()) .As<ICache>().SingleInstance(); //mongodb builder.Register(n => Substitute.For<IMongoDbProvider>()) .As<IMongoDbProvider>().SingleInstance(); _container = builder.Build(); } public static T Resolve<T>() { return _container.Resolve<T>(); } } 支持单元测试的代码(X.3版-只粘贴相关代码) //接口 public interface IXTaService : IApplication{ ResponseMessage<long> GetReturnUseNum(long invitediscountNum, XTaCodeDto codedto); } //实现 public class XTaDiscountService : IXTaDiscountService { private readonly IXTaCodeService _codeService; public XTaDiscountService( IXTaCodeService codeService) { _codeService = codeService; } //将操作使用次数和取消次数的仓储部分挪出去,这里只计算需要退回的使用次数。 public ResponseMessage<long> GetReturnUseNum(long invitediscountNum, XTaCodeDto codedto) { //默认是全部退回使用次数。 long returnNum = invitediscountNum; if (codedto == null) { return ResponseMessage<long>.MakeSucc(0); } //不限制取消的的时候,退回全部使用次数。 if (!codedto.IsLimitCancelUse) { return ResponseMessage<long>.MakeSucc(returnNum); } //已超过的不处理。 if (codedto.CancelUsedCount >= codedto.CancelUseMaxNumber) { return ResponseMessage<long>.MakeSucc(0); } //将要超过的。 if (codedto.CancelUsedCount + invitediscountNum >= codedto.CancelUseMaxNumber) { returnNum = codedto.CancelUsedCount + invitediscountNum - codedto.CancelUseMaxNumber; return ResponseMessage<long>.MakeSucc(returnNum); } return ResponseMessage<long>.MakeSucc(returnNum); } } >初始化数据 private void 验证取消优惠_初始化数据(ref XTaCodeDto codeDto, int usemax = 0, int cancelmax = 0) { if (codeDto == null) { codeDto = new XTaCodeDto() { Id = "11111", CancelUsedCount = 0, UsedCount = 0, PrivateSetting = new PrivateSetting() { IsLimitCancelUse = true, IsCustomCancelUse = true, CancelUseMaxNumber = 1, IsLimitUse = true, IsCustomUse = true, UseMaxNumber = 1 } }; } if (cancelmax > 0) { codeDto.PrivateSetting.CancelUseMaxNumber = cancelmax; codeDto.CancelUsedCount = 0; } if (usemax > 0) { codeDto.PrivateSetting.UseMaxNumber = usemax; codeDto.UsedCount = 0; } } > 模拟报名使用邀请码,递增使用次数,方便批量测试。 private void 初始化数据_模拟报名使用邀请码_递增使用次数(int useNum, XTaCodeDto codeDto) { //mock模拟使用邀请码时,递增的邀请码使用次数返回使用次数。 var usercount = codeSub.IncUseCount(codeDto.Id, Arg.Any<int>()).Returns(x => new ResponseMessage<long>() { Body = (int)codeDto.UsedCount + x.Arg<int>() }); codeDto.UsedCount = codeSub.IncUseCount(codeDto.Id, useNum).Body; } > 模拟取消订单,退回使用次数 private void 验证取消优惠_退回使用次数_V1ForPrivate(long inviteDiscountNum, XTaCodeDto codeDto) { //计算退回使用次数。 var res = discountService.GetReturnUseNum(inviteDiscountNum, codeDto); codeDto.UsedCount -= res.Body; codeDto.CancelUsedCount += inviteDiscountNum; } >实际测试部分 [Fact] public void 验证取消优惠_退回使用次数_最大使用一次_允许取消一次() { XTaCodeDto codeDto = null; 验证取消优惠_初始化数据(ref codeDto, 1, 1); //第一次报名,取消 验证取消优惠_模拟报名使用邀请码_递增使用次数(1, codeDto); 验证取消优惠_退回使用次数_V1ForPrivate(1, codeDto); //第一次取消会退回使用次数。 Assert.True(codeDto.UsedCount == 0 && codeDto.CancelUsedCount == 1); //第二次报名,取消 验证取消优惠_模拟报名使用邀请码_递增使用次数(1, codeDto); 验证取消优惠_退回使用次数_V1ForPrivate(1, codeDto); //第二次取消后,超出允许取消次数限制,不会退回 Assert.True(codeDto.UsedCount == 1 && codeDto.CancelUsedCount == 2); } [Fact] public void 验证取消优惠_退回使用次数_最大使用2次_允许取消两次() { XTaCodeDto codeDto = null; 验证取消优惠_初始化数据(ref codeDto, 2, 2); 验证取消优惠_模拟报名使用邀请码_递增使用次数(1, codeDto); 验证取消优惠_退回使用次数_V1ForPrivate(1, codeDto); Assert.True(codeDto.UsedCount == 0 && codeDto.CancelUsedCount == 1); 验证取消优惠_模拟报名使用邀请码_递增使用次数(2, codeDto); 验证取消优惠_退回使用次数_V1ForPrivate(2, codeDto); Assert.True(codeDto.UsedCount == 1 && codeDto.CancelUsedCount == 3); 验证取消优惠_模拟报名使用邀请码_递增使用次数(1, codeDto); 验证取消优惠_退回使用次数_V1ForPrivate(1, codeDto); Assert.True(codeDto.UsedCount == 2 && codeDto.CancelUsedCount == 4); } 使用单元测试的好处

快速验证结果,不用依赖各种数据库/缓存等环境。

代码指责更单一。

减少bug

方便后期持续集成

可参考连接

使用 dotnet test 和 xUnit 在 .NET Core 中进行 C# 单元测试
nsubstitute 介绍
Autofac介绍
单元测试的艺术

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpssyg.html