public async Task Handle_Success()
        {
            // arrange

            // TODO is 3 really an important value or do we just want any integer?
            var skuId = 3;

            // make a mock just for this test's specific needs!
            var successCommandHandler = new Mock <ICommandHandler <AddToCartCommand> >();

            successCommandHandler
            .Setup(handler => handler.Handle(It.IsAny <AddToCartCommand>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(Result.Success);

            var requestHandler = new AddToCartRequestHandler(successCommandHandler.Object);

            // act
            var result = await requestHandler.Handle(new AddToCartRequest(skuId.ToString()), CancellationToken.None);

            // TODO what if we added another constructor parameter to AddToCartRequestHandler or AddToCartRequest? we could have way more tests than these and we'd have to fix the constructors in all these tests

            // assert
            Assert.IsTrue(result.IsSuccess, "Call should succeed with a valid integer");
            Assert.AreEqual(result.Value, skuId, "Call result should be passed in value as integer.");

            // we can also do this: make sure our mock handler was called with the correct value
            successCommandHandler.Verify(h => h.Handle(It.Is <AddToCartCommand>(c => c.SkuId == skuId), It.IsAny <CancellationToken>()), Times.Once);
        }
        public async Task Handle_Success()
        {
            // arrange

            // make our AutoFixture fixture
            var fixture = new Fixture();

            // let AutoFixture make us some test integer. now it's clear there was nothing special about 3.
            // by default, AutoFixture makes natural 1,2,3,4,5 numbers but we could customize for any other special rules we want (https://blog.ploeh.dk/2010/10/19/Convention-basedCustomizationswithAutoFixture/)
            var skuId = fixture.Create <int>();

            var successCommandHandler = new Mock <ICommandHandler <AddToCartCommand> >();

            successCommandHandler
            .Setup(handler => handler.Handle(It.IsAny <AddToCartCommand>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(Result.Success);

            // TODO we still have to call AddToCartRequestHandler's constructor manually because AutoFixture wouldn't know how to satisfy ICommandHandler<AddToCartCommand> constructor parameter

            fixture.Create <AddToCartRequestHandler>();
            var requestHandler = new AddToCartRequestHandler(successCommandHandler.Object);

            // use AutoFixture builder pattern to make an AddToCartRequest object and setup properties we care about without calling the constructor ourselves
            // if AddToCartRequest got another constructor parameter, the test might not need to be changed at all
            var addToCartRequest = fixture.Build <AddToCartRequest>().With(request => request.SkuId, skuId.ToString).Create();

            // act
            var result = await requestHandler.Handle(addToCartRequest, CancellationToken.None);

            // assert
            Assert.IsTrue(result.IsSuccess, "Call should succeed with a valid integer");
            Assert.AreEqual(result.Value, skuId, "Call result should be passed in value as integer.");
            successCommandHandler.Verify(h => h.Handle(It.Is <AddToCartCommand>(c => c.SkuId == skuId), It.IsAny <CancellationToken>()), Times.Once);
        }
        public async Task Handle_BadInteger()
        {
            // arrange
            var requestHandler = new AddToCartRequestHandler(new SuccessMockAddToCartCommandHandler());

            // act
            var result = await requestHandler.Handle(new AddToCartRequest("Joe"), CancellationToken.None);

            // assert
            Assert.IsTrue(result.IsFailure, "Call should fail because 'Joe' can't be parsed as an integer.");
        }
        public async Task Handle_AddCommandFails()
        {
            // arrange
            var commandHandlerError = "Command handler failed";
            var requestHandler      = new AddToCartRequestHandler(new FailMockAddToCartCommandHandler("Command handler failed"));

            // act
            var result = await requestHandler.Handle(new AddToCartRequest(3.ToString()), CancellationToken.None);

            // assert
            Assert.IsTrue(result.IsFailure, "Call should fail because our mock command handler fails.");
            Assert.AreEqual(commandHandlerError, result.Error, "Request handler should just pass the command handler's error message through when it fails.");
        }
        public async Task Handle_Success()
        {
            // arrange
            var skuId          = 3;
            var requestHandler = new AddToCartRequestHandler(new SuccessMockAddToCartCommandHandler());

            // act
            var result = await requestHandler.Handle(new AddToCartRequest(skuId.ToString()), CancellationToken.None);

            // assert
            Assert.IsTrue(result.IsSuccess, "Call should succeed with a valid integer");
            Assert.AreEqual(result.Value, skuId, "Call result should be passed in value as integer.");
        }
        public async Task Handle_BadInteger()
        {
            // arrange

            // make a mock where we don't care about functionality. we are testing other unrelated behavior and just want to avoid null references.
            var mockCommandHandler = new Mock <ICommandHandler <AddToCartCommand> >();
            var requestHandler     = new AddToCartRequestHandler(mockCommandHandler.Object);

            // act
            var result = await requestHandler.Handle(new AddToCartRequest("Joe"), CancellationToken.None);

            // assert
            Assert.IsTrue(result.IsFailure, "Call should fail because 'Joe' can't be parsed as an integer.");

            // make sure we don't call our command handler when the call should fail before then
            mockCommandHandler.Verify(handler => handler.Handle(It.IsAny <AddToCartCommand>(), It.IsAny <CancellationToken>()), Times.Never);
        }
        public async Task Handle_BadInteger()
        {
            // arrange
            var fixture = new Fixture();

            var mockCommandHandler = new Mock <ICommandHandler <AddToCartCommand> >();
            var requestHandler     = new AddToCartRequestHandler(mockCommandHandler.Object);

            // let AutoFixture create our AddToCartRequest
            var addToCartRequest = fixture.Build <AddToCartRequest>().With(request => request.SkuId, "Joe").Create();

            // act
            var result = await requestHandler.Handle(addToCartRequest, CancellationToken.None);

            // assert
            Assert.IsTrue(result.IsFailure, "Call should fail because a 'Joe' can't be parsed as an integer.");
            mockCommandHandler.Verify(handler => handler.Handle(It.IsAny <AddToCartCommand>(), It.IsAny <CancellationToken>()), Times.Never);
        }
        public async Task Handle_AddCommandFails()
        {
            // arrange
            var commandHandlerError = "Command handler failed";

            // make a mock just for this test's specific needs!
            var failureCommandHandler
                = new Mock <ICommandHandler <AddToCartCommand> >();

            failureCommandHandler
            .Setup(handler => handler.Handle(It.IsAny <AddToCartCommand>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(Result.Failure(commandHandlerError));
            var requestHandler = new AddToCartRequestHandler(failureCommandHandler.Object);

            // act
            var result = await requestHandler.Handle(new AddToCartRequest(3.ToString()), CancellationToken.None);

            // assert
            Assert.IsTrue(result.IsFailure, "Call should fail because our mock command handler fails.");
            Assert.AreEqual(commandHandlerError, result.Error,
                            "Request handler should just pass the command handler's error message through when it fails.");
        }
        public async Task Handle_AddCommandFails()
        {
            // arrange
            var fixture             = new Fixture();
            var commandHandlerError = fixture.Create <string>();

            var failureCommandHandler
                = new Mock <ICommandHandler <AddToCartCommand> >();

            failureCommandHandler
            .Setup(handler => handler.Handle(It.IsAny <AddToCartCommand>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(Result.Failure(commandHandlerError));
            var requestHandler = new AddToCartRequestHandler(failureCommandHandler.Object);

            var addToCartRequest = fixture.Build <AddToCartRequest>().With(request => request.SkuId, fixture.Create <int>().ToString).Create();

            // act
            var result = await requestHandler.Handle(addToCartRequest, CancellationToken.None);

            // assert
            Assert.IsTrue(result.IsFailure, "Call should fail because our mock command handler fails.");
            Assert.AreEqual(commandHandlerError, result.Error,
                            "Request handler should just pass the command handler's error message through when it fails.");
        }