C# 结构化测试代码
目前,我们正在尝试对我们的服务实施一些单元测试。在下面的服务中,将创建订单,并对订单的创建进行审核注册。在编写这两个测试时(因为我们认为应该将测试分开,以获得具有1个责任的测试),这就是我开始的地方:C# 结构化测试代码,c#,unit-testing,xunit,nsubstitute,C#,Unit Testing,Xunit,Nsubstitute,目前,我们正在尝试对我们的服务实施一些单元测试。在下面的服务中,将创建订单,并对订单的创建进行审核注册。在编写这两个测试时(因为我们认为应该将测试分开,以获得具有1个责任的测试),这就是我开始的地方: public class TestPacklineOrderManagementService { [Fact] public void CreateNewProductWhenNoPacklineOrderIsAvailable() { IPackLi
public class TestPacklineOrderManagementService
{
[Fact]
public void CreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(x => null);
var rawProductRepository = Substitute.For<IRawProductRepository>();
rawProductRepository.Get(1).Returns(new RawProduct {Id = 1});
var packlineRepository = Substitute.For<IPackLineRepository>();
packlineRepository.Get(1).Returns(new PackLine {Id = 1});
var auditRegistrationService = Substitute.For<IAuditRegistrationService>();
var packlineOrderManagementService = new PacklineOrderManagementService(packLineOrderRepository, rawProductRepository, packlineRepository, auditRegistrationService);
packlineOrderManagementService.SetProduct(1,1);
packLineOrderRepository.Received()
.Insert(Arg.Is<PackLineOrder>(x => x.PackLine.Id == 1 && x.Product.Id == 1));
}
[Fact]
public void AuditCreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(x=>null);
var rawProductRepository = Substitute.For<IRawProductRepository>();
rawProductRepository.Get(1).Returns(new RawProduct { Id = 1 });
var packlineRepository = Substitute.For<IPackLineRepository>();
packlineRepository.Get(1).Returns(new PackLine { Id = 1 });
var auditRegistrationService = Substitute.For<IAuditRegistrationService>();
var packlineOrderManagementService = new PacklineOrderManagementService(packLineOrderRepository, rawProductRepository, packlineRepository, auditRegistrationService);
packlineOrderManagementService.SetProduct(1, 1);
auditRegistrationService.Received()
.Audit(Arg.Is<PackLineOrderAudit>(item => item.Action == PackLineOrderAction.CreatePacklineOrder));
}
}
公共类TestPacklineOrderManagementService
{
[事实]
public void CreateNewProductWhenOpacklineOrderisAvailable()时创建新产品
{
IPackLineOrderRepository packLineOrderRepository=替换.For();
GetActive(Arg.Any())。返回(x=>null);
var rawProductRepository=Substitute.For();
获取(1).Returns(新的RawProduct{Id=1});
var packlineRepository=替换.For();
packlineRepository.Get(1).Returns(新的PackLine{Id=1});
var auditRegistrationService=Substitute.For();
var packlineOrderManagementService=新的packlineOrderManagementService(packlineorderepository、rawProductRepository、packlineRepository、auditRegistrationService);
packlineOrderManagementService.SetProduct(1,1);
packlineorderepository.Received()
.Insert(参数为(x=>x.PackLine.Id==1&&x.Product.Id==1));
}
[事实]
public void AuditCreateNewProductWhenOpacklineOrderIsAvailable()可用时
{
IPackLineOrderRepository packLineOrderRepository=替换.For();
GetActive(Arg.Any())。返回(x=>null);
var rawProductRepository=Substitute.For();
获取(1).Returns(新的RawProduct{Id=1});
var packlineRepository=替换.For();
packlineRepository.Get(1).Returns(新的PackLine{Id=1});
var auditRegistrationService=Substitute.For();
var packlineOrderManagementService=新的packlineOrderManagementService(packlineorderepository、rawProductRepository、packlineRepository、auditRegistrationService);
packlineOrderManagementService.SetProduct(1,1);
auditRegistrationService.Received()
.Audit(Arg.Is(item=>item.Action==PackLineOrderAction.CreatePacklineOrder));
}
}
正如您可以看到的,有很多重复的代码。为了防止出现这种情况,我尝试对其进行重构,结果产生了以下代码:
public class TestPacklineOrderManagementService2
{
[Fact]
public void CreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository;
IAuditRegistrationService auditRegistrationService;
var packlineOrderManagementService = BuilderForCreateNewProductWhenNoPacklineOrderIsAvailable(out packLineOrderRepository, out auditRegistrationService);
packlineOrderManagementService.SetProduct(1,1);
packLineOrderRepository.Received().Insert(Arg.Any<PackLineOrder>());
}
[Fact]
public void AuditCreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository;
IAuditRegistrationService auditRegistrationService;
var packlineOrderManagementService = BuilderForCreateNewProductWhenNoPacklineOrderIsAvailable(out packLineOrderRepository, out auditRegistrationService);
packlineOrderManagementService.SetProduct(1, 1);
auditRegistrationService.Received()
.Audit(Arg.Is<PackLineOrderAudit>(item => item.Action == PackLineOrderAction.CreatePacklineOrder));
}
private PacklineOrderManagementService BuilderForCreateNewProductWhenNoPacklineOrderIsAvailable(out IPackLineOrderRepository packLineOrderRepository,
out IAuditRegistrationService auditRegistrationService)
{
packLineOrderRepository = CreatePackLineOrderRepository(x => null);
auditRegistrationService = CreateAuditRegistrationService();
var rawProductRepository = CreateRawProductRepository(x => new RawProduct { Id = 1 });
var packlineRepository = CreatePacklineRepository(x => new PackLine { Id = 1 });
var packlineOrderManagementService = new PacklineOrderManagementService(packLineOrderRepository,
rawProductRepository, packlineRepository, auditRegistrationService);
return packlineOrderManagementService;
}
private IPackLineOrderRepository CreatePackLineOrderRepository(Func<CallInfo, PackLineOrder> getActiveResult)
{
IPackLineOrderRepository packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(getActiveResult);
return packLineOrderRepository;
}
private IRawProductRepository CreateRawProductRepository(Func<CallInfo, RawProduct> getResult)
{
IRawProductRepository rawProductRepository = Substitute.For<IRawProductRepository>();
rawProductRepository.Get(1).Returns(getResult);
return rawProductRepository;
}
private IPackLineRepository CreatePacklineRepository(Func<CallInfo, PackLine> getResult)
{
IPackLineRepository packLineRepository = Substitute.For<IPackLineRepository>();
packLineRepository.Get(1).Returns(getResult);
return packLineRepository;
}
private IAuditRegistrationService CreateAuditRegistrationService()
{
return Substitute.For<IAuditRegistrationService>();
}
}
公共类TestPacklineOrderManagementService2
{
[事实]
public void CreateNewProductWhenOpacklineOrderisAvailable()时创建新产品
{
IPackLineOrderRepository packLineOrderRepository;
IAuditRegistrationService审核注册服务;
var packlineOrderManagementService=builderforcreatenewproductwhenopacklineorderisavailable(out packLineOrderRepository,out auditRegistrationService);
packlineOrderManagementService.SetProduct(1,1);
packlineorderepository.Received().Insert(Arg.Any());
}
[事实]
public void AuditCreateNewProductWhenOpacklineOrderIsAvailable()可用时
{
IPackLineOrderRepository packLineOrderRepository;
IAuditRegistrationService审核注册服务;
var packlineOrderManagementService=builderforcreatenewproductwhenopacklineorderisavailable(out packLineOrderRepository,out auditRegistrationService);
packlineOrderManagementService.SetProduct(1,1);
auditRegistrationService.Received()
.Audit(Arg.Is(item=>item.Action==PackLineOrderAction.CreatePacklineOrder));
}
当OpacklineOrderOrderRepository packLineOrderRepository可用时,private PacklineOrderManagementService Builder可用于创建新产品,
out IAUDITREGISTRATION服务审核注册服务)
{
packlineorderepository=createpacklineorderepository(x=>null);
auditRegistrationService=CreateAuditRegistrationService();
var rawProductRepository=CreateRawProductRepository(x=>newRawProduct{Id=1});
var packlineRepository=CreatePacklineRepository(x=>newpackline{Id=1});
var packlineOrderManagementService=新的packlineOrderManagementService(packlineorderepository,
rawProductRepository、packlineRepository、auditRegistrationService);
返回packlineOrderManagementService;
}
专用IPackLineOrderRepository CreatePackLineOrderRepository(Func getActiveResult)
{
IPackLineOrderRepository packLineOrderRepository=替换.For();
GetActive(Arg.Any())。返回(getActiveResult);
返回packlineordrepository;
}
专用IRawProductRepository CreateRawProductRepository(Func getResult)
{
IRawProductRepository rawProductRepository=Substitute.For();
rawProductRepository.Get(1).Returns(getResult);
返回资源库;
}
专用IPackLineRepository CreatePacklineRepository(Func getResult)
{
IPackLineRepository packLineRepository=Substitute.For();
packLineRepository.Get(1).返回(getResult);
退货包装;
}
私有IAuditRegistrationService CreateAuditRegistrationService()
{
返回replacement.For();
}
}
有没有办法为我们的单元测试提供更好的代码基础 更好是非常主观的,这在很大程度上取决于你如何定义它。有些人可能会认为第一个示例更好,因为所有的设置代码都在测试中。根据你上面的代码,我确实有一些反馈
在编写测试时,不要对测试中的系统(SUT)的两个参数使用相同的值,除非它们确实相同,否则会隐藏转置错误。所以,在测试中,你要设置一个替代品,如下所示:
rawProductRepository.Get(1).Returns(new RawProduct {Id = 1});
public class TestPacklineOrderManagementService
{
public class TestSetProduct {
IPackLineOrderRepository _packLineOrderRepository;
IRawProductRepository _rawProductRepository;
// etc
public TestSetProduct() {
_packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
_packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(x => null);
_rawProductRepository = Substitute.For<IRawProductRepository>();
// etc
}
[Fact]
public void CreateNewProductWhenNoPacklineOrderIsAvailable()
{
// Any test specific setup...
_packlineOrderManagementService.SetProduct(1,1);
_packLineOrderRepository.Received()
.Insert(Arg.Is<PackLineOrder>(x => x.PackLine.Id == 1
&& x.Product.Id == 1));
}
[Fact]
public void AuditCreateNewProductWhenNoPacklineOrderIsAvailable()
{
_packlineOrderManagementService.SetProduct(1, 1);
_auditRegistrationService.Received()
.Audit(Arg.Is<PackLineOrderAudit>(item =>
item.Action == PackLineOrderAction.CreatePacklineOrder));
}
}
public class TestSomeOtherScenario {
// tests...
}
}
然后给你的SUT打电话:
packlineOrderManagementService.SetProduct(1,1);
SUT调用中的1是否与存储库设置相关?一点也不清楚哪个1是哪个
这有点主观,但如果您的测试设置完全相同,您真的需要使用不同的断言复制测试吗?真的吗