我们正在使用.NET Core 3.1
。我们要测试是否将正确的消息作为参数传递给我们的电子邮件服务。可能的方法是模拟Send
方法,然后将消息保存到内存队列/列表中。如何在不修改原始界面(IEmailService
)的情况下做到这一点?在我们的模拟服务中,我们需要一个其他方法,该方法可以返回传递到其Send
方法的所有消息,例如List<Message> GetSentEmails()
。
TestsBase.cs
public class TestsBase
{
protected readonly IServiceScope _scope;
protected readonly IPaymentService _paymentService;
protected readonly IEmailService _emailService;
public TestsBase(CustomWebApplicationFactory<Startup> factory)
{
_scope = factory.Services.CreateScope();
_paymentService = _scope.ServiceProvider.GetService<IPaymentService>();
_emailService = _scope.ServiceProvider.GetService<IEmailService>() as EmailServiceMock;
}
}
[CollectionDefinition("MyCollection")]
public class MyCollection : ICollectionFixture<CustomWebApplicationFactory<Startup>>
{
}
PaymentServiceTest.cs
[Collection("MyCollection")]
public class PaymentServiceTest : TestsBase
{
public PaymentServiceTest(CustomWebApplicationFactory<Startup> factory) : base(factory)
{
}
[Fact]
public void ConfirmPaymentTest()
{
// payment service also sends email
_paymentService.Process(new Payment()
{
Amount = 203.12,
Email = "test@test.com",
...
});
// we want to check if correct email was passed to email service
var sentEmails = _emailService.GetSentEmails(); // HOW?
}
}
CustomWebApplicationFactory.cs
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
// mock email service
services.AddScoped<IEmailService, EmailServiceMock>();
});
}
}
EmailService.cs
public class EmailService : IEmailService
{
// implementation
}
public class EmailServiceMock : IEmailService
{
private readonly List<Message> _sentEmails;
public EmailServiceMock()
{
_sentEmails = new List<Message>();
}
// mocked implementation of all the methods
// but we also need access to _sentEmails
public void Send(Message message)
{
_sentEmails.Add(message);
}
}
答案 0 :(得分:1)
我建议您为此使用Moq库。您可以模拟IEmailService
并使用Moq的Callback
方法来捕获将哪些参数传递给Send
方法。
您只需要调整服务的初始化。
[Fact]
public void ConfirmPaymentTest()
{
var sentEmails = new List<Message>();
var emailService = new Mock<IEmailService>();
var paymentService = new PaymentService(emailService.Object);
emailService
.Setup(e => e.Send(It.IsAny<Message>()))
.Callback<Message>(m => sentEmails.Add(m)); // instead of your GetSentEmails()
paymentService.Process(new Payment()
{
Amount = 203.12,
Email = "test@test.com",
...
});
// you can access your sentEmails list here
}
Moq是一个功能强大的库,用于测试.NET。还有更多功能可让您模拟方法的返回,验证调用方法的次数等。