简体   繁体   中英

Using Moq to unit test but the object returns Null

I'm new to using Moq. I am trying to get this unit test to work but my object seems to keep returning null. I saw online that the Setup() must match the actual call. I'm obviously not getting it cause it still doesn't work; it seems to match to me. Here's my code samples.

Test method from test project:

    [TestMethod]
    public void CanPutEmailOptOut()
    {
        var mockParticipant = new PscuParticipant
            {
                ParticipantId = 1,
                DoNotSendCuRewardsEmails = false,
                DoNotSendEarnBonusPointEmail = false,
                CardNumber = "VPZS5zXFUex2SJikkXFVrnvt2/R38yomFXwkslgXNKkgAFsjvt94p1h6J/XUEc6yQ5JzmT6+W8AdxuBSbp9e0SXAN60oHuZtWhAgGHhU+GaxJfCQHitc2+VBSZ/DxwW7Bpw="
            };

        MockBootstrapper.Instance.WithRepositoryData(new[] {mockParticipant});
        var input = new EmailOptOutContract
            {
                DoNotSendCuRewardsEmails = true,
                DoNotSendEarnBonusPointEmail = true
            };

        _affinityOptOutApiClient
            .Setup(
                x =>
                x.CallAffinityOptOutStatus(It.IsAny<string>(), 
                                           It.IsAny<string>(),
                                           mockParticipant.DoNotSendEarnBonusPointEmail,
                                           mockParticipant.ParticipantId))
            .Returns<HindaHttpResponse<OptOutResponse>>(x => new HindaHttpResponse<OptOutResponse>
                {
                    StatusCode = AffinityResultCode.Success,
                    ResponseObject = new OptOutResponse { MemberId = "999999999", Status = "success" }
                });

        var response = Controller.Put(mockParticipant.ParticipantId, input);

        var contract = response.ShouldBeSuccess<SuccessContract>();
        var participant = RepositoryFactory.CreateReadOnly<PscuParticipant>().FirstOrDefault(x => x.ParticipantId == mockParticipant.ParticipantId);
        Assert.AreEqual(input.DoNotSendCuRewardsEmails, participant.DoNotSendCuRewardsEmails);
        Assert.AreEqual(input.DoNotSendEarnBonusPointEmail, participant.DoNotSendEarnBonusPointEmail);
    }

    protected override void Configure()
    {
        MockBootstrapper.Override(config => config.For<IEncryptionService>().Use<EncryptionService>());
        _affinityOptOutApiClient = new Mock<IAffinityOptOutApiClient>(MockBehavior.Strict);
        MockBootstrapper.Override(config => config.For<IAffinityOptOutApiClient>().Use(_affinityOptOutApiClient.Object));
    }

Here's the method from my controller:

    public HttpResponseMessage Put(int participantId, [FromBody]EmailOptOutContract contract)
    {
        if (contract == null)
            return Failure(ApiReturnCodes.InvalidRequestContract
                            , "Invalid Request Contract",
                            string.Format("Contract Is Null in controller method {0}", System.Reflection.MethodBase.GetCurrentMethod()),
                            HttpStatusCode.BadRequest);

        using (new UnitOfWorkScope())
        {
            var participant = GetParticipant(participantId);
            if (participant == null)
            {
                return NotFound(ApiReturnCodes.ParticipantNotFound, "Participant ID not found.");
            }

            participant.DoNotSendCuRewardsEmails = contract.DoNotSendCuRewardsEmails;
            participant.DoNotSendEarnBonusPointEmail = contract.DoNotSendEarnBonusPointEmail;

            string cardNumber = ServiceLocator.Current.GetInstance<IEncryptionService>().Decrypt(participant.CardNumber);
            cardNumber = AesEncrypt(cardNumber);

            string email = null;
            var partic = GetParticipantData(participant.ParticipantId);

            if (partic != null)
                email = partic.Email;

            HindaHttpResponse<OptOutResponse> response =
                _affinityOptOutApiClient.CallAffinityOptOutStatus(cardNumber, email, contract.DoNotSendEarnBonusPointEmail, participant.ParticipantId);

            if (response.StatusCode == AffinityResultCode.Success && response.ResponseObject.Status == "success")
                participant.AffinityMembId = response.ResponseObject.MemberId;
            else
                return BadRequest(ApiReturnCodes.AffinityInternalServerError, response.ExternalErrorMessage);

            return Ok();
        }
    }

The part that comes back null in the controller is

HindaHttpResponse<OptOutResponse> response =
                _affinityOptOutApiClient.CallAffinityOptOutStatus(cardNumber, email, contract.DoNotSendEarnBonusPointEmail, participant.ParticipantId);

The response object is null so when it is checked in the next statement for success, the exception is thrown. Does anyone know what might be wrong with my Setup/Return that's causing problems?

Thanks!!!!

In your controller you're changing participant.DoNotSendCuRewardsEmails to the value in the contract object, which in your setup of that is false. You setup your method to expect true for that parameter as that is the value contained in participant when setup is called. Moq gets the value of the property as is when setup is called, it doesn't lazy evaluate the objects property.

When you setup the mock, you have to use input

x.CallAffinityOptOutStatus(
    It.IsAny<string>(), 
    It.IsAny<string>(),
    input.DoNotSendEarnBonusPointEmail,
    mockParticipant.ParticipantId)

It needs to match the specific call you are making inside the controller.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM