Reputation: 121
My class and method that mocks:
public class EmailService: IEmailService
{
private readonly ISendGridClient _client;
public EmailService(ISendGridClient client)
{
_client = client;
}
public async Task SendAsync(string email, string senderAderess, string senderName, string recipientName, string subject, string content, string htmlContent)
{
var from = new EmailAddress(senderAderess, senderName);
var to = new EmailAddress(email, recipientName);
var plainContent = content;
var msg = MailHelper.CreateSingleEmail(from, to, subject, plainContent, htmlContent);
await _client.SendEmailAsync(msg);
}
}
And unit test for it
public async void EmailService_SendingEmail_EmailSentSuccessfullyAsync()
{
var test = 0;
var mockEmailClient = new Mock<ISendGridClient>();
mockEmailClient.Setup(x => x.SendEmailAsync(new SendGridMessage(), CancellationToken.None)).Callback(() => test++);
var emailSender = new EmailService(mockEmailClient.Object);
await emailSender.SendAsync("[email protected]", "SenderDemo", "Ilya", "EmailServiceUnitTest", "Demo", "Test",
"<strong>Hello</strong>");
Assert.Equal(1, test);
}
And the problem is that my mock does not rise my callback method
Probably the issue because of async nature of the method that mocks, but I really need some your help :)
Upvotes: 4
Views: 3582
Reputation: 247108
The mocked client needs to return a completed Task
to allow the async flow to continue.
This will allow the call back to be invoked when the test is exercised.
public async Task EmailService_SendingEmail_EmailSentSuccessfullyAsync() {
//Arrange
var test = 0;
var mockEmailClient = new Mock<ISendGridClient>();
mockEmailClient
.Setup(x => x.SendEmailAsync(It.IsAny<SendGridMessage>(), It.IsAny<CancellationToken>()))
.Returns(Task.FromResult((object)null)) //<-- needed to allow async flow to continue
.Callback(() => test++);
var emailSender = new EmailService(mockEmailClient.Object);
//Act
await emailSender.SendAsync("[email protected]", "SenderDemo", "Ilya", "EmailServiceUnitTest", "Demo", "Test",
"<strong>Hello</strong>");
//Assert
Assert.Equal(1, test);
}
Also note the changes to the test and the argument matchers used in setting up the mock
Upvotes: 2
Reputation: 3915
You are mocking
SendEmailAsync(new SendGridMessage(), CancellationToken.None)
But calling
_client.SendEmailAsync(msg)
So which one is the right one? Also you don't need this test
variable. Simply use
mockEmailClient.Verify(x => x.SendEmailAsync(...), Times.Once)
You could actually write it this way:
public async Task EmailService_SendingEmail_EmailSentSuccessfullyAsync()
{
var mockEmailClient = new Mock<ISendGridClient>();
mockEmailClient.Setup(x => x.SendEmailAsync(It.IsAny<YourMessageType>()));
var emailSender = new EmailService(mockEmailClient.Object);
await emailSender.SendAsync("[email protected]", "SenderDemo", "Ilya", "EmailServiceUnitTest", "Demo", "Test",
"<strong>Hello</strong>");
mockEmailClient.Verify(x => x.SendEmailAsync(It.IsAny<YourMessageType>()), Times.Once);
}
Upvotes: 3