Moq.MockException: Invocation failed with mock behavior Strict - c#

In the below code, I'm using Moq to test if my Post method is returning CreatedAtRoute StatusCode on successfully addind a book but the test case is failing in Act part when it calls the service and shows the following error:
Moq.MockException: 'IEventRepository.AddEvent(TEMS.Business.Entities.Event) invocation failed with mock behavior Strict.
All invocations on the mock must have a corresponding setup.'
Test Setup and Tear Down:
private Mock<IBookRepository> mockBookRepository;
public override void TestSetup()
{
mockBookRepository = this.CreateAndInjectMock<IBookRepository>();
Target = new BooksController(mockBookRepository.Object);
}
public override void TestTearDown()
{
mockBookRepository.VerifyAll();
}
TestCase:
[Fact]
public void AddBook_ReturnCreatedAtRoute()
{
// to prevent autofixture throwing ThrowingRecursionBehavior
var fixture = new Fixture();
fixture.Behaviors
.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(1));
var books = fixture.Create<Book>();
this.mockBookRepository.Setup(s => s.AddBook(books)).Returns(1);
// Act
BookInputModel booksViewModel = convertDbModelToInputModel(books);
var actual = Target.Post(booksViewModel);
// Assert
var actionResult = Assert.IsType<ObjectResult>(actual);
Assert.Equal((int)HttpStatusCode.Created, actionResult.StatusCode);
this.mockBookRepository.Verify(v => v.AddBook(books), Times.Once);
}
Post Method:
public ActionResult Post(BookInputModel request)
{
try
{
Book addBooks = convertDbModelToInputViewModel(request);
var result = _service.AddBook(addBooks);
if (result == 0) return BadRequest();
return CreatedAtRoute("GetBook", new { id = addBooks.Id }, request);
}
catch (Exception ex)
{
return StatusCode(500, ex.Message);
}
}
Repository:
public int AddBook(Book request)
{
Book newBook = new Book()
{
Name = request.Name,
Author = request.Author,
Publication = request.Publication,
TotalPages = request.TotalPages,
};
if (newBook == null) return 0;
else
{
_context.Book.Add(newBook);
_context.SaveChanges();
return 1;
}
}

Took me a while to realise this little error that was causing the problem - the problem was happening in Act part for the very valid reason as I'm doing setup using DbModel and in Act I'm passing ViewModel(as the Post method in controller requires it) which raises the conflict. Now as far as I'm aware of, the only way to resolve it by using the same model in Post method as of Repository.

Related

Unit testing Delete Method of API producing -> Can not instantiate proxy of class

I'm trying to write a Unit test case for the delete method of the below controller
public class AssetProxyController : Controller
{
private IRiskAssetProxyService _assetProxyService;
public AssetProxyController( IRiskAssetProxyService assetProxyService)
{
_assetProxyService = assetProxyService;
}
[HttpDelete("{assetId}")]
public ActionResult Delete(string assetId)
{
if (_assetProxyService.DeleteAssetProxyMapping(assetId))
{
return Ok("AssetProxy Deleted");
}
else
{
return BadRequest("Unable to delete AssetProxy");
}
}
}
Test
[TestMethod]
public void Delete_ShouldReturnDeleteAssetProxy()
{
//Mock
var mockContext = new Mock<MainDBContext>();
var faker = AutoFaker.Create();
var assetProxyMappings = faker.Generate<List<AssetProxyMapping>>();
var mockAssetProxyDbSet = GetQueryableMockDbSet<AssetProxyMapping>(assetProxyMappings);
mockContext.Setup(c => c.AssetProxyMapping).Returns(mockAssetProxyDbSet);
//Test
var mocklogger = new Mock<ILogger<RiskDataControllerDbAccess>>();
var positiondbaccess = new Mock<RiskAssetProxyDbAccess>(mockContext,mocklogger);
var mockserviceLogger = new Mock<ILogger<RiskAssetProxyService>>();
var positionService = new Mock<RiskAssetProxyService>(positiondbaccess, mockserviceLogger);
var positionController = new AssetProxyController(positionService.Object);
Assert.AreEqual(true, true);
}
But i keep getting the exception
Test method Risk.DataService.UnitTests.API.AssetProxyControllerTests.Delete_ShouldReturnDeleteAssetProxy threw exception:
Castle.DynamicProxy.InvalidProxyConstructorArgumentsException: Can not instantiate proxy of class: Risk.DataServices.RiskAssetProxyService.
Could not find a constructor that would match given arguments:
Moq.Mock`1[Risk.DataServices.RiskAssetProxyDbAccess]
Moq.Mock`1[Microsoft.Extensions.Logging.ILogger`1[Risk.DataServices.RiskAssetProxyService]]
The currently shown test is completely over-engineered based on the shown subject under test.
Given the shown Delete controller action, the test case should be simplified
[TestMethod]
public void AssetProxy_Delete_Should_Return_Ok() {
//Arrange
string assetId = "assetId";
var serviceMock = new Mock<IRiskAssetProxyService>();
serviceMock.Setup(_ => _.DeleteAssetProxyMapping(assetId))
.Returns(true);
AssetProxyController controller = new AssetProxyController(serviceMock.Object);
//Act
ActionResult result = controller.Delete(assetId);
//Assert - using fluent assertions
result.Should().NotBeNull();
string expected = "AssetProxy Deleted";
OkObjectResult okResult = result as OkObjectResult;
okResult.Should().NotBeNull();
string actual = okResult.Value as string;
actual.Should().Be(expected); //same as Assert.AreEqual(expected, actual);
}
Another test case can be done to assert bad requests and would be similar to the case shown above except that the mocked service will be arranged to return false in order to cause the expected behavior and the assertion updated accordingly

How moq File.Delete (IFileSystem) in app MVC Moq

My method which work
[HttpPost]
public async Task<ActionResult> DeleteTeam(int id)
{
Team team = await teamRepository.DeleteTeamAsync(id);
var fileToDeletePath = Path.Combine(Server.MapPath("~/Images/NBAlogoImg/"), team.Path);
if (System.IO.File.Exists(fileToDeletePath))
{
System.IO.File.Delete(fileToDeletePath);
}
if (team != null)
{
TempData["message"] = string.Format("{0} был удален", team.Name);
}
return RedirectToAction("Index", "Player");
}
It's my attempt to make a test, but unsuccessful
[TestMethod]
public async Task CanDeletePlayerAsync()
{
//Arrange
Mock<ITeamRepository> teamsMock = new Mock<ITeamRepository>();
Team team2 = new Team { Id = 2, Name = "Boston" , Path = "CHi.png" };
Team team3 = new Team { Id = 3, Name = "Lakers" };
string fullPath = ("~/Images/NBAlogoImg/");
var serverMock = new Mock<HttpServerUtilityBase>();
serverMock.Setup(x => x.MapPath(fullPath)).Returns(#"s:\work");
var httpContextMock = new Mock<HttpContextBase>();
httpContextMock.Setup(x => x.Server).Returns(serverMock.Object);
var mockFile = new Mock<IFileSystem>();
TeamController controller = new TeamController(teamsMock.Object);
controller.ControllerContext = new ControllerContext(httpContextMock.Object, new RouteData(), controller);
teamsMock.Setup(m => m.DeleteTeamAsync(team2.Id)).Returns(Task.FromResult(team2));
// Act
ActionResult result = await controller.DeleteTeam(team2.Id);
mockFile.Verify(x => x.File.Delete(#"s:\work\file.png"));
//Assert
Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
}
I add the funcional to delete image from app if I delete the team. It works perfect, but how make a test by Moq I try some attempts by unsuccessfully.
I have the error message
Expected invocation on the mock at least once, but was never performed: x => x.File.Delete("s:\work\file.png")
No setups configured.
No invocations performed.
how it fix? I have downloaded IFileSystem and made a moq but verify have been not work.
One obvious solution would be to wrap your File.Delete Call in Custom Class, which implements a Custom interface, For example,
public interface IFileOperations
{
void Delete(string path);
}
For your System Operations, you can create a wrapper class.
public class SystemFileOperations:IFileOperations
{
public void Delete(string path)
{
File.Delete(path);
}
}
Now you can alter your original code to ensure SystemFileOperations is injected at all places where you would require IFileOperations.Delete.
private IFileOperations _fileOperations;
public ControllerName(IFileOperations operations)
{
_fileOperations = operations;
}
Following line would be then replaced
System.IO.File.Delete(fileToDeletePath);
with
_fileOperations.Delete(fileToDeletePath);
And for mocking , you could
var mock = new Mock<IFileOperations>();
mock.Verify(x=>x.Delete(path),Times.AtLeastOnce());
Please note that in your case, due to usage of File.Exists, you might have to mock that as well following the same pattern if you desire so

Unit testing controller methods which return IActionResult

I'm in the process of building an ASP.NET Core WebAPI and I'm attempting to write unit tests for the controllers. Most examples I've found are from the older WebAPI/WebAPI2 platforms and don't seem to correlate with the new Core controllers.
My controller methods are returning IActionResults. However, the IActionResult object only has a ExecuteResultAsync() method which requires a controller context. I'm instantiating the controller manually, so the controller context in this instance is null, which causes an exception when calling ExecuteResultAsync. Essentially this is leading me down a very hacky path to get these unit tests to successfully complete and is very messy. I'm left wondering that there must be a more simple/correct way of testing API controllers.
Also, my controllers are NOT using async/await if that makes a difference.
Simple example of what I'm trying to achieve:
Controller method:
[HttpGet(Name = "GetOrdersRoute")]
public IActionResult GetOrders([FromQuery]int page = 0)
{
try
{
var query = _repository.GetAll().ToList();
int totalCount = query.Count;
int totalPages = (int)Math.Ceiling((double)totalCount / pageSize) - 1;
var orders = query.Skip(pageSize * page).Take(pageSize);
return Ok(new
{
TotalCount = totalCount,
TotalPages = totalPages,
Orders = orders
});
}
catch (Exception ex)
{
return BadRequest(ex);
}
}
Unit test:
[Fact]
public void GetOrders_WithOrdersInRepo_ReturnsOk()
{
// arrange
var controller = new OrdersController(new MockRepository());
// act
IActionResult result = controller.GetOrders();
// assert
Assert.Equal(HttpStatusCode.OK, ????);
}
Assuming something like the
public IActionResult GetOrders() {
var orders = repository.All();
return Ok(orders);
}
the controller in this case is returning an OkObjectResult class.
Cast the result to the type of what you are returning in the method and perform your assert on that
[Fact]
public void GetOrders_WithOrdersInRepo_ReturnsOk() {
// arrange
var controller = new OrdersController(new MockRepository());
// act
var result = controller.GetOrders();
var okResult = result as OkObjectResult;
// assert
Assert.IsNotNull(okResult);
Assert.AreEqual(200, okResult.StatusCode);
}
You can also do cool things like:
var result = await controller.GetOrders();//
var okResult = result as ObjectResult;
// assert
Assert.NotNull(okResult);
Assert.True(okResult is OkObjectResult);
Assert.IsType<TheTypeYouAreExpecting>(okResult.Value);
Assert.Equal(StatusCodes.Status200OK, okResult.StatusCode);
Thanks
Other answers adviced to cast to ObjectResult, but its work only if you return OkObjectResult \ NotFoundObjectResult \ etc. But server could return NotFound\ OkResult which derived from StatusCodeResult.
For example:
public class SampleController : ControllerBase
{
public async Task<IActionResult> FooAsync(int? id)
{
if (id == 0)
{
// returned "NotFoundResult" base type "StatusCodeResult"
return NotFound();
}
if (id == 1)
{
// returned "StatusCodeResult" base type "StatusCodeResult"
return StatusCode(StatusCodes.Status415UnsupportedMediaType);
}
// returned "OkObjectResult" base type "ObjectResult"
return new OkObjectResult("some message");
}
}
I looked at the implementation of all these methods and found that they are all inherited from the IStatusCodeActionResult interface. It seems like this is the most base type that contains StatusCode:
private SampleController _sampleController = new SampleController();
[Theory]
[InlineData(0, StatusCodes.Status404NotFound)]
[InlineData(1, StatusCodes.Status415UnsupportedMediaType)]
[InlineData(2, StatusCodes.Status200OK)]
public async Task Foo_ResponseTest(int id, int expectedCode)
{
var actionResult = await _sampleController.FooAsync(id);
var statusCodeResult = (IStatusCodeActionResult)actionResult;
Assert.Equal(expectedCode, statusCodeResult.StatusCode);
}
A good way to do that is like this:
[Fact]
public void GetOrders_WithOrdersInRepo_ReturnsOk() {
// arrange
var controller = new OrdersController(new MockRepository());
// act
var result = controller.GetOrders();
// assert
var okResult = Assert.IsType<OkObjectResult>(result);
Assert.IsNotNull(okResult);
Assert.AreEqual(200, okResult.StatusCode);
}
You also can use ActionResult class as a controller result (assuming you have type Orders).
In that case you can use something like this:
[ProducesResponseType(typeof(Orders), StatusCodes.Status200OK)]
public ActionResult<Orders> GetOrders()
{
return service.GetOrders();
}
and now in unit tests you have:
Assert.IsInstanceOf<Orders>(result.Value);
Besides, this is the recommendation of Microsoft - https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-2.2#actionresultt-type
Unfortunately, I don't know why using Ok method
return Ok(service.GetOrders());
doesn't map it properly.
public async Task CallRxData_ReturnsHttpNotFound_ForInvalidJobNum_ReturnsStoredRxOrder()
{
var scanInController = new ScanInController(_logger, _scanInService);
var okResult = await scanInController.CallRxData(rxOrderRequest);
var notFoundResult = await scanInController.CallRxData(invalidRxOrderRequest);
var okResultWithScanInCheckFalse = await scanInController.CallRxData(rxOrderRequest);
var okResultWithEmptyAelAntiFakeDatas = await scanInController.CallRxData(rxOrderRequest);
// Assert
Assert.That(okResult, Is.TypeOf<OkObjectResult>());
Assert.That(notFoundResult, Is.TypeOf<NotFoundObjectResult>());
Assert.IsFalse(((okResultWithScanInCheckFalse as ObjectResult).Value as RxOrder).IsSecurity);`enter code here`
}

Moq setup returns null

So, I'm starting to learn an implement UniTesting on a Web Api project I'm working on. What's happening is that when I setup a mock a call this one returns null instead of the value I'm telling to returns. I don't know why a similiar Setup works but this one just doesn't.
Here is my Test Class
namespace API.Tests.Web
{
[TestClass]
public class MaterialsControllerTest
{
private MaterialsController controller;
private Mock<IRTWRepository> repository;
private Mock<IModelFactory> factory;
private Mock<IRTWAPIIdentityService> identityService;
List<MaterialAccepted> materials;
MaterialAccepted material;
[TestInitialize]
public void Initialize()
{
repository = new Mock<IRTWRepository>();
factory = new Mock<IModelFactory>();
identityService = new Mock<IRTWAPIIdentityService>();
controller = new MaterialsController(repository.Object);
material = new MaterialAccepted()
{
business = true,
businessService = EnumRecycleCenterService.Dropoff,
residential = false,
residentialService = EnumRecycleCenterService.Pickup,
note = "this a note",
Category = new Category()
{
name = "Books"
}
};
materials = new List<MaterialAccepted>()
{
new MaterialAccepted() { business=true,businessService=EnumRecycleCenterService.Dropoff,residential=false,residentialService=EnumRecycleCenterService.Pickup,note="this a note"},
new MaterialAccepted() { business=false,businessService=EnumRecycleCenterService.Dropoff,residential=true,residentialService=EnumRecycleCenterService.Pickup,note="this a note"},
};
}
[TestMethod]
public void Post_ShouldReturnBadRequestWhenMaterialAcceptedModelValidationFails()
{
//arrange
repository.Setup(r => r.RecycleCenterRepository.Get(3)).Returns(() => new RecycleCenter());
controller.ModelState.AddModelError("error", "unit test error");
//act
var actionResult = controller.Post(2, new MaterialAcceptedModel());
Assert.IsInstanceOfType(actionResult, typeof(BadRequestResult));
}
}
}
Here is the action in the Controller I'm trying to test
[HttpPost]
[Route("api/recyclecenters/{rcid}/materials/")]
public IHttpActionResult Post(int rcid, [FromBody]MaterialAcceptedModel model)
{
try
{
if (model != null)
{
var recycleCenter = TheRepository.RecycleCenterRepository.Get(rcid);
if (recycleCenter == null)
return NotFound();
if (!ModelState.IsValid)
return BadRequest(ModelState);
var entity = TheModelFactory.Parse(model);
if (entity == null) return BadRequest("Could not read material accepted in body");
if (TheRepository.MaterialAcceptedRepository.Get(recycleCenter.RecycleCenterId, entity.Category.name) != null)
return Conflict();
recycleCenter.Materials.Add(entity);
if (TheRepository.SaveAll())
{
string locationHeader = Url.Link("Materials", new { rcid = rcid, name = model.category.ToLower() });
return Created<MaterialAcceptedModel>(locationHeader, TheModelFactory.Create(entity));
}
return BadRequest("Could not save to the database");
}
return BadRequest();
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
If I run this test it will fail because it returns an instancy type of NotFoundResult instead of a BadRequestResult, and this is happening because the test method stops in this line
if (recycleCenter == null)
return NotFound();
But this test it suppose to stop on this line
if (!ModelState.IsValid)
return BadRequest(ModelState);
Any ideas why this
repository.Setup(r => r.RecycleCenterRepository.Get(3)).Returns(() => new RecycleCenter());
is returning null when it should return a new RecycleCenter
It seems like you are setting up the repository mock for rcid = 3, and calling the repository in the controller with rcid = 2.
//arrange
repository.Setup(r => r.RecycleCenterRepository.Get(3)).Returns(() => new RecycleCenter());
controller.ModelState.AddModelError("error", "unit test error");
//act
var actionResult = controller.Post(2, new MaterialAcceptedModel());
Try calling it with rcid = 3
var actionResult = controller.Post(3, new MaterialAcceptedModel());
or change the Moq setup parameter to It.IsAny<int>()

How to mock SendGrid

I am trying to write a unit test for a method I wrote which sends out an email with SendGrid.
My method is something like this:
public async Task SendEmail(TemplatedMailMessage emailMessage)
{
if (String.IsNullOrWhiteSpace(emailMessage.Html) || String.IsNullOrWhiteSpace(emailMessage.From.ToString()) || !emailMessage.To.Any())
{
throw new Exception("Html, From or To is empty");
}
try
{
// Send the email
await this.TransportWeb.DeliverAsync(emailMessage.GetSendGridMessage());
}
catch (Exception ex)
{
//do stuff
}
//log success
}
the TransportWeb is a property which is set in my constructor through a parameter so I can create a mock object.
public EmailManager(Web transportWeb = null)
{
this.TransportWeb = transportWeb ?? SetupSendGrid();
}
In my test method I am trying to mock the TransportWeb (of type SendGrid.Web) property:
[TestMethod]
public async Task SendEmail_ValidEmailTemplateAndNoParameters_EmailIsSent()
{
//ARRANGE
var templatedMailmessage = new Mock<TemplatedMailMessage>();
var transportWeb = new Mock<Web>();
transportWeb.SetupAllProperties();
transportWeb.Setup(x => x.DeliverAsync(It.IsAny<ISendGrid>()));
var emailManager = new EmailManager(transportWeb.Object);
//ACT
await emailManager.Send(templatedMailmessage.Object);
//ASSERT
transportWeb.Verify(x => x.DeliverAsync(It.IsAny<ISendGrid>()), Times.Once());
}
However, I get the following error:
Invalid setup on a non-virtual (overridable in VB) member: x =>
x.DeliverAsync
Does anybody have an idea how I can fix this?
Okay I fixed it :)
You should not use the Web class but ITransport interface:
var transport = new Mock<ITransport>();
transport.SetupAllProperties();
transport.Setup(x => x.DeliverAsync(It.IsAny<SendGridMessage>())).ReturnsTask();
var em = new EmailManager(transport.Object);
I also used the extensions methods created by Simon V.

Categories