0

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]]
techno
  • 6,100
  • 16
  • 86
  • 192
  • `var positiondbaccess = new Mock(mockContext,mocklogger);` you are not mocking an interface here. mocking concrete classes has restrictions, and is also not recommended as not being very S-O-L-I-Dish. https://stackoverflow.com/questions/50282374/c-sharp-mock-interface-vs-mock-class – Michael Schönbauer Apr 08 '22 at 07:21
  • @MichaelSchönbauer Changed that, this produces a new error `Test method Risk.DataService.UnitTests.API.AssetProxyControllerTests.Delete_ShouldReturnDeleteAssetProxy threw exception: System.ArgumentException: Constructor arguments cannot be passed for interface mocks.` – techno Apr 08 '22 at 07:24
  • well, i think the problem goes a bit deeper, because now that you you did change it so that no concrete types are mocked, you must remove the constructor argument from moq - if thats not possible (you have structured dependencies, instead of flat dependencies), you could try to get more information here https://stackoverflow.com/questions/7414704/mocking-objects-with-moq-when-constructor-has-parameters – Michael Schönbauer Apr 08 '22 at 07:33

1 Answers1

1

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

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Thanks.I'm just new to unit testing.How can I verify that a record is actually deleted ? Shall I create a context of the production db , start a transaction -> delete records -> verify-> roll back.As per this documentation https://learn.microsoft.com/en-us/ef/core/testing/testing-with-the-database – techno Apr 08 '22 at 16:04