C# 通过解析获取实例的方法的单元测试<;T>;自动传真机
我在尝试为服务上的方法实现单元测试时遇到了一个问题。 该项目的架构有点麻烦,更不用说 问题在于,在要测试的方法中,它调用另一个方法来获取另一个服务的实例,下面是一个小怪物:C# 通过解析获取实例的方法的单元测试<;T>;自动传真机,c#,unit-testing,dependency-injection,autofac,C#,Unit Testing,Dependency Injection,Autofac,我在尝试为服务上的方法实现单元测试时遇到了一个问题。 该项目的架构有点麻烦,更不用说 问题在于,在要测试的方法中,它调用另一个方法来获取另一个服务的实例,下面是一个小怪物: public void SendOrderEmail(string orderCode) { Order order= GetOrderService().SerachByCode(orderCode); .... Send email with the order .... } private IOrde
public void SendOrderEmail(string orderCode)
{
Order order= GetOrderService().SerachByCode(orderCode);
.... Send email with the order ....
}
private IOrderService GetOrderService()
{
return OrderService = AutofacDependencyResolver.Current.ApplicationContainer.Resolve<IOrderService>();
}
public void SendOrderEmail(字符串orderCode)
{
Order Order=GetOrderService().SerachByCode(orderCode);
..随订单发送电子邮件。。。。
}
私有IOrderService GetOrderService()
{
return OrderService=AutofacDependencyResolver.Current.ApplicationContainer.Resolve();
}
请不要问为什么一个服务调用另一个服务,或者为什么该服务没有在构造函数中注入,正如我说的,这个项目的架构在某些方面很奇怪。
我只需要知道为这样的方法实现单元测试的方法是什么
谢谢大家! 我会重构一点代码,让实现此方法的类通过构造函数注入IOrderService,保存实例,然后使用它, 通过这种方式,您可以在测试期间注入伪IOrderService(或使用Automock):)
如果您真的无法更改构造函数,那么您可以使用属性来设置IOrderService,正如其他人所说,而且您可能已经意识到,您确实希望像这样重构类,并尽可能使用构造函数注入。服务位置通常被认为是一种反模式(),它特别使像这样的单元测试变得更加困难和不那么透明 然而,如果您绝对不能重构,您仍然可以通过为您通过服务位置访问的服务提供不同的注册,使这样的方法在某种程度上可以测试 在您的情况下,如果您有:
public class EmailSender
{
public void SendOrderEmail(string orderCode)
{
Order order = GetOrderService().SearchByCode(orderCode);
//....Send email with the order ....
}
private IOrderService GetOrderService()
{
return AutofacDependencyResolver.Current.ApplicationContainer.Resolve<IOrderService>();
}
}
使用该设置,您只需要提供您正在测试的特定方法所需的模拟,假设您可以轻松地在autofacdependencysolver
中设置容器,以便并行运行生产和测试配置。在测试项目中使用xUnit、Moq和Autofac时,可能会出现以下情况:
public class EmailSenderTests
{
private readonly Mock<IOrderService> _orderService;
public EmailSenderTests()
{
// to set up the test fixture we'll create a mock OrderService and store a reference to the mock itself for validation later on
_orderService = new Mock<IOrderService>();
var mockOrder = new Order();
_orderService.Setup(os => os.SearchByCode(It.IsAny<string>()))
.Returns(mockOrder);
}
private IContainer GetTestContainer()
{
// here we're adding just one registration we need, setting the mocked OrderService instance to be used for IOrderService
var builder = new ContainerBuilder();
builder.Register(c => _orderService.Object)
.As<IOrderService>();
return builder.Build();
}
[Fact]
public void SendEmail()
{
AutofacDependencyResolver.SetContainer(GetTestContainer()); // set the test container on the global singleton
var sender = new EmailSender();
sender.SendOrderEmail("abc"); // internally the email sender will retrieve the mock IOrderService via service location
// make any assertions here, e.g.
_orderService.Verify(os=>os.SearchByCode("abc"), Times.Exactly(1));
}
}
公共类EmailSenderTests
{
私有只读模拟订单服务;
公共电子邮件发送者测试()
{
//为了设置测试夹具,我们将创建一个mock OrderService,并存储对mock本身的引用,以便稍后进行验证
_orderService=newmock();
var mockOrder=新订单();
_orderService.Setup(os=>os.SearchByCode(It.IsAny()))
.退货(订单);
}
私有IContainer GetTestContainer()
{
//在这里,我们只添加一个需要的注册,将模拟的OrderService实例设置为用于IOrderService
var builder=new ContainerBuilder();
builder.Register(c=>\u orderService.Object)
.As();
返回builder.Build();
}
[事实]
public void sendmail()
{
AutofacDependencyResolver.SetContainer(GetTestContainer());//在全局单例上设置测试容器
var sender=新的EmailSender();
sender.SendOrderEmail(“abc”);//在内部,电子邮件发件人将通过服务位置检索模拟IOrderService
//在这里做任何断言,例如。
_Verify(os=>os.SearchByCode(“abc”),Times.execute(1));
}
}
Cab是否为autofac容器提供模拟,以便返回的IOrderService本身就是模拟?您可能需要向autofac注册一个模拟服务,而不是我应该在单元测试项目中安装autofac。对吗?
public class EmailSenderTests
{
private readonly Mock<IOrderService> _orderService;
public EmailSenderTests()
{
// to set up the test fixture we'll create a mock OrderService and store a reference to the mock itself for validation later on
_orderService = new Mock<IOrderService>();
var mockOrder = new Order();
_orderService.Setup(os => os.SearchByCode(It.IsAny<string>()))
.Returns(mockOrder);
}
private IContainer GetTestContainer()
{
// here we're adding just one registration we need, setting the mocked OrderService instance to be used for IOrderService
var builder = new ContainerBuilder();
builder.Register(c => _orderService.Object)
.As<IOrderService>();
return builder.Build();
}
[Fact]
public void SendEmail()
{
AutofacDependencyResolver.SetContainer(GetTestContainer()); // set the test container on the global singleton
var sender = new EmailSender();
sender.SendOrderEmail("abc"); // internally the email sender will retrieve the mock IOrderService via service location
// make any assertions here, e.g.
_orderService.Verify(os=>os.SearchByCode("abc"), Times.Exactly(1));
}
}