How do I get a result from a mocked service? Note: It works properly. I'm just trying to get the test going.
The service:
public interface ISendgridService
{
Task<Response> SendAsync(IEmailMessage emailMessage);
}
// The test
[TestMethod]
public async Task SendEmailTest()
{
// Arrange
var mockSendgrid = new Mock<ISendgridService>();
var response = new Mock<Func<SendGrid.Response>>();
mockSendgrid.Setup(s => s.SendAsync(It.IsAny<IEmailMessage>()))
.ReturnsAsync(response.Object.Invoke);
var emailMessage = _builder.CreateNew<EmailMessage>()
.With(e => e.From = _sendgridConfiguration.SenderEmail)
.With(e => e.FromName = _sendgridConfiguration.SenderName)
.With(e => e.To = Faker.Internet.Email())
.Build();
// Act
var result = await mockSendgrid.Object.SendAsync(emailMessage);
// Assert
// result is null // How do I get a value?
}
I am a little confused as to what you're trying to test. Usually, you'd act on a concrete class under test, not a stubbed object.
Pseudo code below:
public class SendGridService : ISendGridService {
public async Task<bool> SendAsync() {
//code that sends the email
}
}
Your test would be like:
//Act
var subject = new SendGridService();
var result = await subject.SendAsync();
//Assert
Assert.IsTrue(result);
You've set up the Mock<ISendgridService> to return something - it uses another mock - Mock<Func<SendGrid.Response>> and returns the result of invoking that Func.
But you haven't set up the Mock<Func<SendGrid.Response>> to return anything, so it doesn't.
In other words, when you do this:
mockSendgrid.Setup(s => s.SendAsync(It.IsAny<IEmailMessage>()))
.ReturnsAsync(response.Object.Invoke);
What does response.Object.Invoke return? response.Object is a Mock<Func<SendGrid.Response>>, but it hasn't been set up to return anything.
A Func is actually much easier to mock without using Moq. You can just do this:
// Create the thing you need the function to return, whatever that looks like.
var response = new SendGrid.Response(someStatusCode, body, headers);
// create a function that returns it.
var functionMock = new Func<SendGrid.Response>(() => response);
That depends on what you want to test of the app, if you are trying to test whether it sends an email or not, you shouldnt be using a mock class if you want to actually test if it sends. What you should mock is the content of the email.
Now if what you want to check is that certain steps including the email works (integrating all of them in a method) thats another matter, in this case you should use a dummy task that returns a dummy response.
Related
I have created a unit test method that verifies method is called, below is the code for the same.The method builds email object and calls GeneratePDF method which returns bytes further BuildEmailInfo method returns email object.
public class SMTPEmailSender : IEmailSender
{
private IPDFCreater _pdfCreater;
public SMTPEmailSender(IPDFCreater pdfCreater)
{
_pdfCreater = pdfCreater;
}
public Email BuildEmailInfo(string sMTPServerUrl, FaxMailDTO faxAsMailRequest)
{
Email email=null;
try
{
var otp = new PDFData { OTP =faxAsMailRequest.OTP};
email = new Email
{
SMTPServerUrl = sMTPServerUrl,
Encoding = Encoding.UTF8,
ToAddress = faxAsMailRequest.ToEmailAddress,
ToAddressDisplayName = faxAsMailRequest.ToAddressDisplayName,
FromAddress = faxAsMailRequest.FromEmailAddress,
Subject = faxAsMailRequest.Subject,
Body = faxAsMailRequest.Body,
FromAddressDisplayName = faxAsMailRequest.FromAddressDisplayName,
ContentStream = new MemoryStream(_pdfCreater.GeneratePDF(otp)),
AttachmentName = faxAsMailRequest.FaxFileName
};
}
catch(Exception ex)
{
Log.Error("Method : BuildEmailInfo. Exception raised while building email data : {#Message}", ex.Message, ex);
}
return email;
}
Below is my unit test code , whenever I execute this it throws an error Expected invocation on the mock at least once, but was never performed: x=>x.GeneratePDF(pdfdata). Also Let me know if it is right way to perform the test
public class SMTPEmailSenderTest
{
private SMTPEmailSender _sMTPEmailSender;
Mock<IPDFCreater> _mockPdfCreator;
public SMTPEmailSenderTest()
{
_mockPdfCreator = new Mock<IPDFCreater>();
_sMTPEmailSender = new SMTPEmailSender(_mockPdfCreator.Object);
}
[Theory]
[MemberData(nameof(GetFaxAsMailObject))]
public void BuildEmailInfoTest_ReturnsValidEmailObject(FaxMailDTO faxMailDTO)
{
string smpturl = "localhost";
var otp = new PDFData { OTP = faxMailDTO.OTP };
var result = _sMTPEmailSender.BuildEmailInfo(smpturl, faxMailDTO);
_mockPdfCreator.Verify(x => x.GeneratePDF(otp));
}
}
This line:
_mockPdfCreator.Verify(x => x.GeneratePDF(otp));
performs a 'verification'. This is an assertion that checks if method .GeneratePDF has been called on _mockPdfCreator with otp as its parameter.
All .Verify methods from the interface of the Mock object are used to check if some method or property were called. You can also provide some filters to see if certain parameters were passed, for example:
_myMock.Verify(x => x.FooBar(5));
_myMock.Verify(x => x.FooBar(123));
_myMock.Verify(x => x.FooBar(It.IsAny<int>());
_myMock.Verify(x => x.FooBar(It.Is<int>(number => (number-5)%3 > 10));
all of these check if FooBar was alled on _myMock, but each of them looks only at calls that used certain values of parameters: 5, 123, anything-that-is-int, or (...).
You cannot use .Verify to check for the return value.
There's no such option there.
Why? Think about it. You've had:
_mockPdfCreator = new Mock<IPDFCreater>();
....
_mockPdfCreator.Verify(x => x.GeneratePDF(otp));
The _mockPdfCreator is your mock object. Not a real thing. It's a tiny ghost that acts as if it were some IPDFCreater.
There's not a slightest bit of a real implementation there.
How can you expect that GeneratePDF returns anythin meaningful?
It just won't. Nothing's there behind it. If anything called that method GeneratePDF, it would return NULL (or throw exception, depending on mocking mode: Loose/Strict).
...unless you SET UP your mock to do it differently:
var theThing = ...;
_mockPdfCreator = new Mock<IPDFCreater>();
_mockPdfCreator.Setup(x => x.GeneratePDF(It.IsAny<...>())).Returns(theThing);
....
// ... now check what `GeneratePDF` returned?!
Now of anything calls GeneratePDF method, it will return theThing. Alright.
But you knew that already. There's nothing to check. You set up GeneratePDF to return the thing, so there's not a slightest point to check what GeneratePDF returned. It's your mock and your setup!
Sooo, if anything called GeneratePDF, then NULL would be returned, because there's no setup for GeneratePDF. However, as Verify proved, the GeneratePDF was never called. This means that when you created the SMTPEmailSender giving it the mock as parameter:
_mockPdfCreator = new Mock<IPDFCreater>();
_sMTPEmailSender = new SMTPEmailSender(_mockPdfCreator.Object);
and then in test you've had:
....
var result = _sMTPEmailSender.BuildEmailInfo(smpturl, faxMailDTO);
_mockPdfCreator.Verify(x => x.GeneratePDF(otp));
then, apparently, the _sMTPEmailSender.BuildEmailInfo didn't fancy calling GeneratePDF at all.
Why? No idea. Most probably there was something either in smpturl or faxMailDTO that was considered invalid for this use case and that generate-pdf step was skipped. Check the Result. See if there are any errors or messages that would tell you anything about why it did not even try to call GeneratePDF.
Also note that the verification you wrote were
x => x.GeneratePDF(otp)
That's pretty specific. It has hard-coded reference to otp. So maybe it was called, but with different parameter value?
Try adding:
var result = _sMTPEmailSender.BuildEmailInfo(smpturl, faxMailDTO);
_mockPdfCreator.Verify(x => x.GeneratePDF(It.IsAny<PDFData>())); // <-
_mockPdfCreator.Verify(x => x.GeneratePDF(otp));
or something along the lines and see which Verify fails. If the former passes and the latter fails, than everything's mostly fine, it's just not the exact OTP that you expected (maybe _sMTPEmailSender cloned it? etc).
In any chance that the former fails, then it means that GeneratePDF is truly not called even a single time, and then it means you have to learn why BuildEmailInfo with params (smpturl, faxMailDTO) doesn't do what you expect. You've got a try-catch-log there. Maybe some nullreferenceexption? But I doubt it.
You've got there:
[MemberData(nameof(GetFaxAsMailObject))] /// <==== B
public void BuildEmailInfoTest_ReturnsValidEmailObject(FaxMailDTO faxMailDTO) // <--- A
{
...
var otp = new PDFData { OTP = faxMailDTO.OTP }; //<--- C
...
_mockPdfCreator.Verify(x => x.GeneratePDF(otp)); //<---D
So, the faxMailDTO is from GetFaxAsMailObject. The BuildEmailInfo gets it via params and passes part of it to GeneratePDF. Then you assert in Verify that D uses newly-constructed otp from line C. That just can't work. The faxMailDTO from A+B so from GetFaxAsMailObject certainly DOES NOT contain otp from C and certainly will not pass otp object to GeneratePDF. The GeneratePDF will get some other PDFData object that came from faxMailDTO from A+B.
I think I've said enough and covered all issues with your test setup.. You almost have it right. Good luck!
Verifications on mock objects should be your 'last resort' in unit tests. Think about it: is an actual requirement violated if the PDF creator does not call the GeneratePDF method? The user only cares that the PDF was generated.
In this case, you can verify the outcome of the BuildEmailInfo method directly, for example:
var result = _sMTPEmailSender.BuildEmailInfo(smpturl, faxMailDTO);
var expectedBytes = ...; // TODO - get the expected byte[] array from somewhere
Assert.Equal(expectedBytes, result.ContentStream.ToArray());
Additionally, you may be able to write this test without mocking the dependency at all? If the actual PDF creator object can be called to generate a byte[] array in memory, you could just use the real object instead of mocking it.
I understand IMemoryCache.Set is an extension method so it can not be mocked. People have provided workarounds to such situation e.g as one by the NKosi here. I am wondering how I can achieve that for my data access layer where my MemoryCache returns a value and when not found it gets data from the db, set it to the MemoryCache and return the required value.
public string GetMessage(int code)
{
if(myMemoryCache.Get("Key") != null)
{
var messages= myMemoryCache.Get<IEnumerable<MyModel>>("Key");
return messages.Where(x => x.Code == code).FirstOrDefault().Message;
}
using (var connection = dbFactory.CreateConnection())
{
var cacheOptions = new MemoryCacheEntryOptions { SlidingExpiration = TimeSpan.FromHours(1) };
const string sql = #"SELECT Code, Message FROM MyTable";
var keyPairValueData = connection.Query<KeyPairValueData>(sql);
myMemoryCache.Set("Key", keyPairValueData, cacheOptions );
return keyPairValueData.Where(x => x.Code == code).FirstOrDefault().Message;
}
}
Following is my Unit Test - And off course it is not working as I can't mock IMemoryCache
[Fact]
public void GetMessage_ReturnsString()
{
//Arrange
// Inserting some data here to the InMemoryDB
var memoryCacheMock = new Mock<IMemoryCache>();
//Act
var result = new DataService(dbConnectionFactoryMock.Object, memoryCacheMock.Object).GetMessage(1000);
//assert xunit
Assert.Equal("Some message", result);
}
The first thing I would say is why not use a real memory cache? It would verify the behavior much better and there's no need to mock it:
// Arrange
var memCache = new MemoryCache("name", new NameValueCollection());
//Act
var result = new DataService(dbConnectionFactoryMock.Object, memCache).GetMessage(1000);
// Assert: has been added to cache
memCache.TryGetValue("Key", out var result2);
Assert.Equal("Some message", result2);
// Assert: value is returned
Assert.Equal("Some message", result);
If you really want to mock it out, here's a guide on how to do that:
Because it's an extension method, you need to make sure that it can be called as is. What happens in your case is that the extension method will call into the mock. Since you provide no expected behavior, it will probably fail.
You need to look at the code for the extension method, check what it accesses and then ensure that your mock complies with the expected behavior. The code is available here:
https://github.com/aspnet/Caching/blob/master/src/Microsoft.Extensions.Caching.Abstractions/MemoryCacheExtensions.cs#L77
This is the code:
public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value, MemoryCacheEntryOptions options)
{
using (var entry = cache.CreateEntry(key))
{
if (options != null)
{
entry.SetOptions(options);
}
entry.Value = value;
}
return value;
}
So, from that, you can see that it accesses CreateEntyand expects an object from it. Then it calls SetOptions and assigns Value on the entry.
You could mock it like this:
var entryMock = new Mock<ICacheEntry>();
memoryCacheMock.Setup(m => m.CreateEntry(It.IsAny<object>())
.Returns(entryMock.Object);
// maybe not needed
entryMock.Setup(e => e.SetOptions(It.IsAny<MemoryCacheEntryOptions>())
...
When you do this, the extension method will be called on the mock and it will return the mocked entry. You can modify the implementation and make it do whatever you want.
I have a simple hub that I am trying to write a test for with FakeItEasy and the verification of calling the client is not passing. I have the example working in a separate project that uses MOQ and XUnit.
public interface IScheduleHubClientContract
{
void UpdateToCheckedIn(string id);
}
public void UpdateToCheckedIn_Should_Broadcast_Id()
{
var hub = new ScheduleHub();
var clients = A.Fake<IHubCallerConnectionContext<dynamic>>();
var all = A.Fake<IScheduleHubClientContract>();
var id= "123456789";
hub.Clients = clients;
A.CallTo(() => all.UpdateToCheckedIn(A<string>.Ignored)).MustHaveHappened();
A.CallTo(() => clients.All).Returns(all);
hub.UpdateToCheckedIn(id);
}
I'm using Fixie as the Unit Test Framework and it reports:
FakeItEasy.ExpectationException:
Expected to find it once or more but no calls were made to the fake object.
The sample below works in XUnit & MOQ:
public interface IScheduleClientContract
{
void UpdateToCheckedIn(string id);
}
[Fact]
public void UpdateToCheckedIn_Should_Broadcast_Id()
{
var hub = new ScheduleHub();
var clients = new Mock<IHubCallerConnectionContext<dynamic>>();
var all = new Mock<IScheduleClientContract>();
hub.Clients = clients.Object;
all.Setup(m=>m.UpdateToCheckedIn(It.IsAny<string>())).Verifiable();
clients.Setup(m => m.All).Returns(all.Object);
hub.UpdateToCheckedIn("id");
all.VerifyAll();
}
I'm not sure what I've missed in the conversion?
You're doing some steps in a weird (it looks to me, without seeing the innards of your classes) order, and I believe that's the problem.
I think your key problem is that you're attempting to verify that all.UpdateToCheckedIn must have happened before even calling hub.UpdateToCheckedIn. (I don't know for sure that hub.UpdateToCheckedIn calls all.UpdateToCheckedIn, but it sounds reasonable.
There's another problem, where you configure clients.Setup to return all.Object, which happens after you assert the call to all.UpdateToCheckedIn. I'm not sure whether that's necessary or not, but thought I'd mention it.
The usual ordering is
arrange the fakes (and whatever else you need)
act, but exercising the system under test (hub)
assert that expected actions were taken on the fakes (or whatever other conditions you deem necessary for success)
I would have expected to see something more like
// Arrange the fakes
var all = A.Fake<IScheduleHubClientContract>();
var clients = A.Fake<IHubCallerConnectionContext<dynamic>>();
A.CallTo(() => clients.All).Returns(all); // if All has a getter, this could be clients.All = all
// … and arrange the system under test
var hub = new ScheduleHub();
hub.Clients = clients;
// Act, by exercising the system under test
var id = "123456789";
hub.UpdateToCheckedIn(id);
// Assert - verify that the expected calls were made to the Fakes
A.CallTo(() => all.UpdateToCheckedIn(A<string>.Ignored)).MustHaveHappened();
I want to test this (Controller Method) :
public async Task<IActionResult> Create(SecurityQuestionViewModel securityQuestion)
{
if (ModelState.IsValid)
{
SecurityQuestion dataModel = new SecurityQuestion();
dataModel.questionText = securityQuestion.QuestionText;
await _securityRepository.AddAsync(dataModel);
return RedirectToAction("Index");
}
else
{
return View();
}
}
My unit test (so far) looks like this ?
public async Task ModelContainsNewObjectAfterCreate()
{
//Arrange
_repository = new Mock<ISecurityQuestionRepository>();
_repository.Setup(repo => repo.GetAllAsync()).Returns(Task.FromResult(securityQuestion()));
_controller = new SecurityQuestionsController(_repository.Object, _mapper);
SecurityQuestion dataModel = new SecurityQuestion();
dataModel.questionText = "This is the new added question";
SecurityQuestionViewModel sqvm = new SecurityQuestionViewModel();
sqvm.QuestionText = dataModel.questionText;
//Act
var result = await _controller.Create(sqvm);
//Assert
var viewResult = Assert.IsType<RedirectToActionResult>(result);
_repository.Verify(r => r.AddAsync(dataModel), Times.Once);
}
The viewResult passes.
The _repository verify does not.
It feels like I need to verify that the AddAsync method ran (would add a record to the existing repository). Perhaps my setup is wrong
It also feels like I need to validate the number of "questions" in the repository after the AddAsync method ran.
I am trying to understand what would constitute an adequate test and how to simulate the "Add" with the Moq.
Any insight would be appreciated.
This Post seems close to what I want.
You can test only following things in your action:
The case when the model is valid.
The case when the model is invalid.
There are only two cases. If the first case is satisfied you can verify that AddAsync() is executed with any parameter which is type SecurityQuestion.
You can mock AddAsync() like this:
repository.Setup(r => r.AddAsync(It.IsAny<SecurityQuestion>())
.Returns(Task.FromResult(false));
And verify:
repository.Verify(r => r.AddAsync(It.IsAny<SecurityQuestion>()), Times.Once);
That is all which you can!
You cannot mock SecurityQuestion model because it uses new keyword and your code which try to mock should be removed.
This is all you need to do because your entire logic is if/else statement. Everything else will be executed normally. Only another thing which can behave unexpectedly is if AddAsync() throws an exception.
The verify fails because the model was created within the method under test so it does not match. what you can do is use the It.Is with a predicate that matches the model properties
_repository.Verify(r => r.AddAsync(It.Is<SecurityQuestion>(m => m.questionText == dataModel.questionText)), Times.Once);
I have a unit test that should return the specified object but it is returning null.
The Data Provider to test:
public class PlanDataProvider : BaseDomainServiceProvider, IPlanDataProvider
{
//CTOR
public PlanDataProvider(IDataAccessTemplate template, IEntityStore entityStore) : base(template, entityStore)
{
}
public async Task<DefaultActionPlan> GetDefaultActionPlan(string referenceListId)
{
var objectId = GetObjectId(referenceListId);
var defaultActionPlan = await Template.InvokeAsync(context => Task.FromResult(EntityStore.GetEntityById<DefaultActionPlan, ObjectId>
(
context.ActivityContext as IDataAccessContext,
typeof(DefaultActionPlan).FullName,
objectId
)));
}
}
The Test:
public async Task GetPlan_BadPlanID()
{
//Arrange
string badPlanId = "57509afbc6b48d3f33b2dfcd";
...snip...
DefaultActionPlan jj = new ObjectId(badPlanId);
//create EntityStore object
var dataxs = Substitute.For<IDataAccessContext>();
var estore = Substitute.For<IEntityStore>();
estore.GetEntityById<DefaultActionPlan, ObjectId>(
dataxs,
typeof(DefaultActionPlan).FullName,
new ObjectId(badPlanId))
.Returns(Task.FromResult(jj).Result);
var dataAccessTemplate = Substitute.For<IDataAccessTemplate>();
PlanDataProvider pdp = new PlanDataProvider(dataAccessTemplate, estore);
//Act
var t = await pdp.GetDefaultActionPlan(badPlanId);
//Now this confuses me as the compiler thinks t is DefaultActionPlan NOT Task<DefaultActionPlan>???
}
Anyway t returns null eferytime and debugging the test t is null because the GetDefaultActionPlan is not returning jj but instead null??
What am I missing to have jj returned?
Edit:
Both Eris and Gabe rightly pointed out that my Mock of the IEntityStore was not sufficient as that value...even though it specifies a return will not get passed to the wrapping InvokeAsync thus I needed to Mock the InvokeAsync as well.
Gabe's answer was slightly off as passing Arg.Any does not satisfy the InvokeAsync needed parms. However I do not fault him for this as I spent an hours tracking the inheritance chain across multiple projects (this is a big company). Something he does not have access to do.
In the end here is the code that resulted in success:
var estore = Substitute.For<IEntityStore>();
var dataAccessTemplate = Substitute.For<IDataAccessTemplate>();
dataAccessTemplate.InvokeAsync(context => Task.FromResult(
estore.GetEntityById<DefaultActionPlan>(
dataxs, typeof(DefaultActionPlan).FullName, new ObjectId(badPlanId))))
.ReturnsForAnyArgs(jj);
var pdp = new PlanDataProvider(dataAccessTemplate, estore);
While I don't see this in your code, I will assume that GetDefaultActionPlan returns the defaultActionPlan variable, and that Template.InvokeAsync is referring to the IDataAccessTemplate passed in via the constructor.
It looks like you are missing a mock return value for Template.InvokeAsync, and since it is wrapping the other call its return value is the only one you care about:
var estore = Substitute.For<IEntityStore>();
var dataAccessTemplate = Substitute.For<IDataAccessTemplate>();
dataAccessTemplate.InvokeAsync(context => Task.FromResult(Arg.Any<DefaultActionPlan>)
.ReturnsForAnyArgs(jj);
var pdp = new PlanDataProvider(dataAccessTemplate, estore);