Setting up background work item using MoQ - c#

I am new to unit testing and I am having some difficulties with unit testing background workers.
Method being tested
[HandleExceptions(LoggerName)]
public override IHttpActionResult ValidateToken(string auth_token)
{
var response = new HttpResponseMessage();
var userInfo = this._userInfoService.CreateUserInfoModel(auth_token);
response.StatusCode = HttpStatusCode.BadRequest;
if (userInfo.Status.IsSuccess)
{
//-- I want to test if the following worker is calling RunPlayerDetailsWorkflow method exactly once.
_taskScheduler.QueueBackgroundWorkItem(task =>
this._playerDetailsService.RunPlayerDetailsWorkflow(userInfo.UserID, userInfo.ServerID));
response.StatusCode = HttpStatusCode.OK;
}
response.Content = new StringContent(_userInfoService.ParseUserInfo(userInfo));
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("text/plain");
return this.ResponseMessage(response);
}
Test method
[Test]
public void TestValidateToken_Should_Call_PlayerDetailsService_RunPlayerDetailsWorkflow_Exactly_Once()
{
// Arrange
var userInfoModel = AdminControllerHelpers.CreateUserInfoModel();
userInfoModel.Status = ETIStatus.CreateSuccess();
_mockUserInfoService
.Setup(m => m.CreateUserInfoModel(It.IsAny<string>()))
.Returns(userInfoModel);
_mockUserInfoService
.Setup(s => s.ParseUserInfo(userInfoModel))
.Returns(_randomString);
_mockPlayerService
.Setup(m => m.RunPlayerDetailsWorkflow(userInfoModel.UserID, userInfoModel.ServerID));
//-- this is where I got the error.
_mockTaskScheduler
.Setup(t => t.QueueBackgroundWorkItem(
obj => _mockPlayerService.Object.RunPlayerDetailsWorkflow(userInfoModel.UserID,
userInfoModel.ServerID)));
// Act
_controller.ValidateToken(It.IsAny<string>());
// Assert
_mockPlayerService
.Verify(m => m.RunPlayerDetailsWorkflow(userInfoModel.UserID, userInfoModel.ServerID), Times.Exactly(1));
}
Even though I am setting up everything correctly (at least to me) I get following error:
An exception of type 'System.ArgumentException' occurred in System.Core.dll but was not handled in user code. Additional information: Argument types do not match
Task Scheduler interface which I am mocking
public interface ITaskScheduler
{
/// <summary>
/// Schedules a task which can run in the background, independent of any request.
/// </summary>
/// <param name="workItem"> A unit of execution.</param>
void QueueBackgroundWorkItem(Action<CancellationToken> workItem);
}

Change the setup to expect an action and then use the callback to execute the mock
_mockTaskScheduler
.Setup(_ => _.QueueBackgroundWorkItem(It.IsAny<Action<CanellationToken>>()))
.Callback((Action<CancellationToken> action) => action(CancellationToken.None));
Also when exercising the method under test, no need to use It.IsAny<>(). Just pass a value.
// Act
_controller.ValidateToken(String.Empty);
// Assert
_mockPlayerService
.Verify(m => m.RunPlayerDetailsWorkflow(userInfoModel.UserID, userInfoModel.ServerID), Times.Exactly(1));
Should be able to exercise the test as expected now.

Related

Writing mocks using moq for a method

I have the method below I will like to unit test. I am using mstest. Notice how CatService
is used to call 2 other methods
This line of code gets a service of Type T
_provider.GetNecessaryService<IJohnsonProject>() gets a service of Type T
Here is the method
public async Task<(bool, string)> AddDataAsync(DataDto firstSet)
{
try
{
var CatService = _provider.GetNecessaryService<IJohnsonProject>();
var dto = _mapper.Map<MyDto>(firstSet);
var reply = await CatService.AddInfoAsync(dto);
if (!string.IsNullOrEmpty(firstSet.ImageMime) && firstSet.Image.Length > 0)
{
await CatService.AddPictureAsync(reply.Id, firstSet.Image, firstSet.ImageMime);
}
return (true, reply.Id);
}
catch (Exception ex)
{
return (false, ex.Message);
}
}
I started thinking I have to write some Mocks. The first one I have below should return a service type of T
[TestMethod]
public async Task MyFirstTest(){
var CatService = _mockprovider.Setup(x => x.GetNecessaryService<IJohnsonProject>());
}
What is the best way to Mock these two lines ?
var reply = await CatService.AddInfoAsync(dto);
await CatService.AddPictureAsync(reply.Id, firstSet.Image, firstSet.ImageMime);
_provider is a factory pattern, therefore you need to implement a mocked up version of the objects that it returns too:
var mockedJohnsonProject = new Mock<IJohnsonProject>();
mockedJohnsonProject.Setup(x=>x.AddInfoAsync(It.IsAny<MyDto>());
var CatService = _mockprovider.Setup(x => x.GetNecessaryService<IJohnsonProject>())
.Returns(mockedJohnsonProject.Object);

How do I get a result from this mocked service?

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.

Unit Testing a Service with Moq & xUnit

Sorry, this is likely a very amateur question, but I am struggling to understand how to use Moq properly. I am quite new to unit testing as a whole, but I think I'm starting to get the hang of it.
So here's my question... I have this snippet of code below which is using a TestServer in Visual Studio that I using for am Unit Testing... I'm trying to mock IGamesByPublisher so that my test is not reliant on data in the repository (or would it be better to mock GamesByPublisher?... Or do I need to do both?)
public static TestServerWithRepositoryService => new TestServer(services =>
{
services.AddScoped<IGamesByPublisher, GamesByPublisher();
}).AddAuthorization("fake.account", null);
[Fact] // 200 - Response, Happy Path
public async Task GamesByPublisher_GamesByPublisherLookup_ValidRequestData_Produces200()
{
// Arrange
var server = ServerWithRepositoryService;
// Act
var response = await server.GetAsync(Uri);
// Assert
Assert.NotNull(response);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
Here is the IGamesByPublisher
public interface IGamesByPublisher interface.
{
Task<IEnumerable<Publisher>> Execute(GamesByPublisherQueryOptions options);
}
}
I tried
public static TestServerWithRepositoryService => new TestServer(services =>
{
services.AddScoped<Mock<IGamesByPublisher>, Mock<GamesByPublisher>>();
}).AddAuthorization("fake.account", null);
And then I tried
// Not exactly what I attempted, but that code is long gone...
var mock = new Mock<IGamesByPublisher >();
var foo = new GamesByPublisherQueryOptions();
mock.Setup(x => x.Execute(foo)).Returns(true);
I didn't really find great documentation on using Moq, just the quick start guide on GitHub, which I wasn't sure how to apply (probably my own level of experience at fault there...).
I am obviously missing some fundamentals on using Moq...
You were close.
public static TestServerWithRepositoryService => new TestServer(services => {
var mock = new Mock<IGamesByPublisher>();
var publishers = new List<Publisher>() {
//...populate as needed
};
mock
.Setup(_ => _.Execute(It.IsAny<GamesByPublisherQueryOptions>()))
.ReturnsAsync(() => publishers);
services.RemoveAll<IGamesByPublisher>();
services.AddScoped<IGamesByPublisher>(sp => mock.Object);
}).AddAuthorization("fake.account", null);
The above creates the mock, sets up its expected behavior to return a list of publishers any time Execute is invoked with a GamesByPublisherQueryOptions.
It then removes any registrations of the desired interface to avoid conflicts and then registers the service to return the mock any time the interface is requested to be resolved.

MOQ error setups not matched with Async / Await Unit Test

I am trying to figure out what I am missing here. My test runs fine but my MOQ VerifyAll is throwing an exception.
[TestMethod]
public async Task ActionPlanDataProvider_GetActionPlanReferenceList_ReturnsValid()
{
try
{
//Arrange
Mock<IActionPlanDataProvider> moqAPlan = new Mock<IActionPlanDataProvider>();
//moqAPlan.Setup(x => x.GetActionPlanReferenceList()).ReturnsAsync(new ActionPlanReferenceList());
moqAPlan
.Setup(x => x.GetActionPlanReferenceList("1"))
.Returns(Task.FromResult(new ActionPlanReferenceList()));
//Act
var d = await moqAPlan.Object.GetActionPlanReferenceList("1234123");
//Assert
moqAPlan.VerifyAll();
}
catch (Exception ex)
{
string a = ex.Message;
throw;
}
}
The following setups were not matched...
I'm wondering if this is because the way async runs that my MOQ doesn't see mocked object method call?
That happens when the Setup is not used. You set up the mock to use GetActionPlanReferenceList("1") but called GetActionPlanReferenceList("1234123").
So according to moq what you executed didn't match what you setup.
You could either match the expected arguments or try
moqAPlan
.Setup(x => x.GetActionPlanReferenceList(It.IsAny<string>()))
.Returns(Task.FromResult(new ActionPlanReferenceList()));
which will let the method accept any string vai the It.IsAny<string>() expression argument

How do i test a case where i cant reference to the same property?

Test case: when i edit a customer, and repository for some reason could not update, service should return this exception.
Method to test:
public bool EditCustomer(CustomerViewModel customerToEdit)
{
return _repository.Update(customerToEdit.ToEntity());
}
[TestFixtureSetUp]
public void SetUp()
{
this._customerRepositoryMock = Substitute.For<ICustomerRepository>();
this._customerService = new CustomerService(this._customerRepositoryMock);
}
[Test]
public void EditCustomerShouldReturnTrueWhenCustomerIsCreated()
{
var c = new CustomerViewModel();
_customerRepositoryMock.Update(c.ToEntity()).Returns(x => {throw new Exception();});
Assert.Throws<Exception>(() => _customerService.EditCustomer(c));
}
This test case will ofcourse not work, because customerToEdit.ToEntity() != c.ToEntity() because they dont refer to the same object. Are there any way to test this case? Or should i rewrite whole application, and make Controllers responsible for convertion from and to entitys?
I'm not sure which library you are using, but using Moq you could do it in a number of ways:
var viewModel = new CustomerViewModel();
var customerRepositoryMock = new Mock<ICustomerRepository>();
// If you just want to test out the behavior of an exception being thrown,
// regardless of what is passed in
customerRepositoryMock
.Setup(r => r.Update(It.IsAny<CustomerViewModel>()))
.Throws<Exception>();
// If you need to throw an exception when the viewmodel contains certain properties
customerRepositoryMock
.Setup(r => r.Update(It.Is<CustomerViewModel>(c => c.Id == viewModel.Id)))
.Throws<Exception>();
// If you need to throw an exception with specific properties, and verify those
customerRepositoryMock
.Setup(r => r.Update(It.Is<CustomerViewModel>(c => c.Id == viewModel.Id)))
.Throws(new Exception("some message"));
You can then do your asserts as you already had them defined.
I omitted your ToEntity() method here as the point is to show you more "loose" ways of determining equality on your input parameters, such as by type or by properties, instead of just by reference.

Categories

Resources