khellang / Middleware

Various ASP.NET Core middleware
MIT License
806 stars 110 forks source link

How do you Mock a bad request using ProblemdetailsFactory #171

Open developer9969 opened 2 years ago

developer9969 commented 2 years ago

Hi I would like to create a set of unit test using MOQ and would like to mock simple things like badRequest -NotFound etc...

I have tried a few things like below to set up the mock

`    public static void SetupMockProblemDetails(this Mock<ProblemDetailsFactory> mockProblemFactory)
    {
        mockProblemFactory
            .Setup(_ => _.CreateProblemDetails(
                It.IsAny<HttpContext>(),
                It.IsAny<int?>(),
                It.IsAny<string>(),
                It.IsAny<string>(),
                It.IsAny<string>(),
                It.IsAny<string>())
            )
            .Returns(new ProblemDetails())
            .Verifiable();
    }`

But I Crash when I map the mockProblemFactory.Object. How do you test BadRequest with your middleware?

 `  [Theory]
[InlineData("", "")]
public async Task GetCustomer_WithivalidId_BadRequest(string id)
{
    var mockRepo = new Mock<ICustomerRepository>();
    mockRepo.Setup(x => x.GetCustomer(It.IsAny<string>())).ReturnsAsync(() => new GetCustomerResponse { Customer = null }).Verifiable();

    var mockLogger = new Mock<ILogger<CustomerController>>();

    var mockProblemFactory = new Mock<Hellang.Middleware.ProblemDetails.ProblemDetailsFactory>();
    mockProblemFactory.SetupMockProblemDetails();
    var sut = new CustomerController(mockRepo.Object, mockLogger.Object);
    sut.ProblemDetailsFactory = mockProblemFactory.Object;

`

Thanks for any suggestions

khellang commented 2 years ago

Hi @developer9969! 👋🏻

But I Crash when I map the mockProblemFactory.Object

What's the crash? Any errors or details worth mentioning? I have little to go on here...

I would like to create a set of unit test

It would probably be much better to run in-memory integration tests for these scenarios.

developer9969 commented 2 years ago

Hi @khellang
thanks you so much for your prompt reply.

It would probably be much better to run in-memory integration tests for these scenarios.

I was wondering that too, but because where I work all the other controller tests that do not use problemdetails (I introduced it) have unit tests with MOQ testing for badrequest- not result found etc.. I found myself struggling mocking problem details...

I

Castle.DynamicProxy.InvalidProxyConstructorArgumentsException HResult=0x80070057 Message=Can not instantiate proxy of class: Hellang.Middleware.ProblemDetails.ProblemDetailsFactory. Could not find a parameterless constructor. Source=Castle.Core StackTrace: at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(Type proxyType, List1 proxyArguments, Type classToProxy, Object[] constructorArguments) at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors) at Moq.CastleProxyFactory.CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, Object[] arguments) at Moq.Mock1.InitializeInstance() at Moq.Mock1.OnGetObject() at Moq.Mock.get_Object() at Moq.Mock1.get_Object() etc...

I dont get the error when mocking using the microsoft problem details.. but still not sure if you can actually mock bad request etc... or I should just give up on those.? If is possible do you have a snippet?

miryalarohith-10144 commented 8 months ago

I was facing error: Source=Castle.Core StackTrace: at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(Type proxyType, List1 proxyArguments, Type classToProxy, Object[] constructorArguments) at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors) at Moq.CastleProxyFactory.CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, Object[] arguments) at Moq.Mock1.InitializeInstance() at Moq.Mock1.OnGetObject() at Moq.Mock.get_Object() at Moq.Mock1.get_Object() at Microsoft.Crm.Extensibility.UnitTests.NonRelational.OrganizationInformationControllerTests.UnitTestBuilder..ctor(String requestUri, String apiName, Mock`1 handlerMock) in C:\CDS\src\Microsoft.Cds.UnitTests\Microsoft.Crm.Extensibility.UnitTests\NonRelational\OrganizationInformationControllerTests.cs:line this.Unit = mockOrganizationInformationController.Object; at Microsoft.Crm.Extensibility.UnitTests.NonRelational.OrganizationInformationControllerTests.GetServiceEndPoint_ExecuteSucceed() in C:\CDS\src\Microsoft.Cds.UnitTests\Microsoft.Crm.Extensibility.UnitTests\NonRelational\OrganizationInformationControllerTests.cs:line UnitTestBuilder builder = new UnitTestBuilder(this.baseUri, "getserviceendpoint", handlerMock); at System.RuntimeMethodHandle.InvokeMethod(Object target, Void* arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr args, BindingFlags invokeAttr)

        public UnitTestBuilder(string requestUri, string apiName, Mock<HttpMessageHandler> handlerMock)
        {
            requestUri += apiName;
            IOrganizationContext organizationContext = CreateMockIOrganizationContext();
            Mock<IExecutionContext> executionContext = new Mock<IExecutionContext>();
            Guid orgId = MetadataForMetadata.DummyOrgIdForMetadataForMetadataXmlLoader;
            executionContext = new Mock<IExecutionContext>();
            Mock<IExecutionContextFactory> executionContextFactory = new Mock<IExecutionContextFactory>();
            executionContextFactory.Setup(x => x.CreateInstance(It.IsAny<Guid>())).Returns(executionContext.Object);
            Mock<DynamicMetadataCache> mockCache = new Mock<DynamicMetadataCache>();
            Mock<IEntityDescription> entityDescription = new Mock<IEntityDescription>();
            entityDescription.Setup(x => x.LogicalName).Returns("testTable");
            entityDescription.Setup(x => x.ObjectTypeCode).Returns(1024);
            Mock<IEntityMetadataDataProvider> entityMetadataProvider = new Mock<IEntityMetadataDataProvider>();
            EntityMetadata entityMetadata = new EntityMetadata(entityDescription.Object, entityMetadataProvider.Object);
            mockCache.Setup(m => m.TryGetEntity(It.IsAny<int>())).Returns(entityMetadata);
            executionContext.SetupGet(x => x.MetadataCache).Returns(mockCache.Object);

            Mock<ILocatorService> locatorService = new Mock<ILocatorService>();

pragma warning disable CS0618 // 'Do not use this test-only method that modifies static production state. Instead, enable unit test mocking by providing an interface-wrapped instance of the type you need to vary as a constructor parameter.'

            LocatorService.TestSetInstance(locatorService.Object);

pragma warning restore CS0618 // 'Do not use this test-only method that modifies static production state. Instead, enable unit test mocking by providing an interface-wrapped instance of the type you need to vary as a constructor parameter.'

            HttpClient httpClient = new HttpClient(handlerMock.Object);

            OrganizationSettingsClient organizationSettingsClient = new OrganizationSettingsClient(
                requestUri,
                httpClient);

if NETFRAMEWORK

            var configuration = new HttpConfiguration();
            Mock<IResourceDiscovery> mockResourceDiscovery = new Mock<IResourceDiscovery>();
            mockResourceDiscovery.Setup(x => x.GetGeoEndpointName(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns("nrd.us-il002.gateway.test.island.powerapps.com");
            this.Unit = new OrganizationInformationController(
                executionContextFactory.Object,
                organizationContext,
                new OrganizationSettings(new Lazy<OrganizationSettingsClient>(() => organizationSettingsClient), new Mock<ILogger>().Object, mockResourceDiscovery.Object))
            {
                Request = new HttpRequestMessage(HttpMethod.Get, requestUri)
            };
            this.Unit.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = configuration;

else

            var mockOrganizationInformationController = new Mock<OrganizationInformationController>(
                organizationContext,
                new OrganizationSettings(new Lazy<OrganizationSettingsClient>(() => organizationSettingsClient), new Mock<ILogger>().Object));

pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

            mockOrganizationInformationController.Setup(oic => oic.Ok(It.IsAny<object?>()))
                .Returns(new OkObjectResult(@"{""isAuditNoSqlReadEnabled"":true,""customEntityStorageDetails"":{""1024"":15678},""auditSize"":78}"));

pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

            var mockHttpContext = AspNetCoreTestHelper.CreateMockHttpContext(new Uri(requestUri), method: "GET");

            this.Unit = mockOrganizationInformationController.Object;

            this.Unit.ControllerContext = new ControllerContext()
            {
                HttpContext = mockHttpContext.Object
            };

endif

            this.Unit.Request.Headers.Add("x-ms-correlation-id", Guid.NewGuid().ToString());
            this.Unit.Request.Headers.Add("Request-Id", Guid.NewGuid().ToString());
            this.Unit.Request.Headers.Add("Client-Session-Id", Guid.NewGuid().ToString());
            this.Unit.Request.Headers.Add("Client-Activity-Id", Guid.NewGuid().ToString());
            this.Unit.Request.Headers.Add("x-nls-debug", "true");
        }