I try to write some unit tests for my controller.
[HttpPost]
public Answer RegistrationSocial([FromBody] RegistrationSocialRequest newUser)
{
var answer = new Answer();
try
{
userProvider.RegistrationSocial(newUser.Email,
newUser.PhoneNumber,
newUser.SocialProviderId,
newUser.SocialProvider,
UserIP);
answer.Result = 0;
}
catch (Exception e)
{
answer.Result = 2;
answer.Description = "Server error";
}
return answer;
}
private string UserIP
{
get { return HttpContext.Current.Request.UserHostAddress; }
}
RegistrationSocialRequest is just a POCO object which is needed for Model Binding. This method return json and I want to track its change, just to be sure that clients can work with it. For testing I use Moq and MSTest. Here is the test method.
[TestMethod]
public void IsJsonOkRegistrationSocial()
{
//Arrange
Mock<IUserProvider> mock = new Mock<IUserProvider>();
mock.Setup(m => m.RegistrationSocial("lincoln#usa.gov",
"123",
"0987654321",
1,
"192.0.0.1"));
UserController controller = new UserController(mock.Object);
Answer answerOk = new Answer
{
Result = 0,
Caption = "Ok",
Description = null,
Data = null
};
//Action
var answer = controller.RegistrationSocial(new RegistrationSocialRequest
{
SocialProvider = 1,
Email = "lincoln#usa.gov",
PhoneNumber = "123",
SocialProviderId = "0987654321"
});
//Assert
Assert.AreEqual(JsonConvert.SerializeObject(answerOk),
JsonConvert.SerializeObject(answer));
}
But method thrown exception, because UserIP is null, and I can`t undestand why. I am new in unit testing, maybe this all could be done in easier way.
The HttpContext.Current.Request.UserHostAddress isn't set as you expect when you run the code outside the web environment, when you run your unit test.
On solution is to create an 'IHttpContextService' with a method 'GetUserIP'. In this way you could call this service in the UserIP-property and when testing you could mock the interface.
Related
Having some issues setting up my mock data for a unit test in my API. The data is retrieved from a service.
Here is my endpoint and how the data is retrieved:
RetrieveExceptionReportSessionDatesResponse response
= await ResolveServiceClient().RetrieveExceptionReportSessionDatesAsync(new RetrieveExceptionReportSessionDatesRequest());
List<ExceptionReportSessionDataModel> result
= GetSessionData(response.RetrieveExceptionReportSessionDatesResult);
if (result != null && result.Count > 0)
{
logText = LogFormatter.Format(
WebUtilities.GetUser((ClaimsIdentity)HttpContext.User.Identity),
startTime, DateTime.Now, Privilege.EditSession,
"Get Exception Report Session Data", "Exception Report Session Data retrieved successfully.");
logger.LogInfo(logText);
}
else
{
logText = LogFormatter.Format(
WebUtilities.GetUser((ClaimsIdentity)HttpContext.User.Identity),
startTime, DateTime.Now, Privilege.ViewOrderExceptionReport,
"Get exception report session data", "Exception report session data is null or empty.");
logger.LogWarn(logText);
}
return Ok(result);
Here is what I have so far in setting up my unit test:
//Arrange
List<ExceptionReportSessionDataModel> sessionData = new List<ExceptionReportSessionDataModel>()
{
new ExceptionReportSessionDataModel() {SessionName = "Session1", ReportFiles = null },
new ExceptionReportSessionDataModel() {SessionName = "Session2", ReportFiles = null },
new ExceptionReportSessionDataModel() {SessionName = "Session3", ReportFiles = null }
};
//NEED HELP HERE
var ERSessionDataMock = new Mock<>();
ERSessionDataMock.Setup(x => x.).Returns();
var loggerMock = new Mock<ILogger>();
loggerMock.Setup(x => x.LogInfo(null));
GetSessionData Method:
public List<ExceptionReportSessionDataModel> GetSessionData(string sessionData)
{
List<ExceptionReportSessionDataModel> reports = new List<ExceptionReportSessionDataModel>();
if (!string.IsNullOrWhiteSpace(sessionData))
{
string[] splitString = sessionData.Split("\n", StringSplitOptions.RemoveEmptyEntries);
foreach (string s in splitString)
{
string[] temp = s.Split(",", StringSplitOptions.RemoveEmptyEntries);
List<string> files = new List<string>();
for (int index = 1; index < temp.Length; index++)
{
files.Add(temp[index]);
}
reports.Add(new ExceptionReportSessionDataModel()
{
ReportFiles = files,
SessionName = temp[0]
});
}
}
return reports;
}
I need help setting up the ERSessionDataMock
It is impossible to know without seeing how the GetSessionData method is implemented. But here are some quick suggestions:
Inject your ServiceClient as a dependency instead of calling a method to get it. It needs to either:
be an interface (like IServiceClient) - then in your Startup.cs class:
services.AddScoped<IServiceClient>(sp => ResolveServiceClient().Result);
or the RetrieveExceptionReportSessionDatesAsync method needs to be virtual or abstract so you can override it with a mock:
public virtual RetrieveExceptionReportSessionDatesAsync(RetrieveExceptionReportSessionDatesRequest request);
Then in your test, create a response variable that will exercise the GetSessionData in a certain way to get either an empty List<ExceptionReportSessionDataModel> or not, depending on the test (again, no way to know exactly how without seeing your logic):
var response = new RetrieveExceptionReportSessionDatesResponse();
And override the RetrieveExceptionReportSessionDatesAsync method on the mock:
var serviceClient = new Mock<IServiceClient>();
serviceClient
.Setup(x => x.RetrieveExceptionReportSessionDatesAsync(It.IsAny<RetrieveExceptionReportSessionDatesRequest>()))
.Returns(response);
Now, if you've setup response in a way that triggers GetSessionData to return a List<ExceptionReportSessionDataModel> that has Count > 0, you can verify that log message, otherwise verify the opposite log message.
But IMO, the way you've written this code makes unit testing a chore. You don't seem to be taking advantage of dependency injection.
UPDATE:
It seems you can either assign response as:
var response = new RetrieveExceptionReportSessionDatesResponse
{
RetrieveExceptionReportSessionDatesResult = Guid.NewGuid().ToString()
}
and verify that logger.LogInfo is called with Privilege.EditSession, or assign response as:
var response = new RetrieveExceptionReportSessionDatesResponse
{
RetrieveExceptionReportSessionDatesResult = string.Empty
}
and verify that logger.LogWarn is called with Privilege.ViewOrderExceptionReport.
Just one more observation - is there an off-by-one error in the for loop? (It is staring at index 1)
I'm trying to Unit Test below Web API controller.
[IdentityBasicAuthentication]
[Authorize]
[HttpPost]
public HttpResponseMessage GetOrderByQR([FromBody]string id)
{
try
{
var identity = HttpContext.Current.User.Identity as ClaimsIdentity;
var user = UserManager().IdentifyToken(identity);
_orderManager.CheckOrderQRFraud(id);
return Request.CreateResponse(HttpStatusCode.OK, _orderManager.GetSingleOrderWithUserPaymentAccountBy(user.UserID, id));
}
catch (BusinessException ex)
{
return CreateRawStringResponse(HttpStatusCode.NotFound, ex.Message);
}
}
But below test method throws null exception on IdentifyToken() as there is no current user, I understand that.
[TestMethod]
public void GetOrderByQR_Returns_OK_On_Successful_Request()
{
string orderID = "4B854B3D-397E-425F-AEAF-00F7B4110021";
var testResponse = _orderController.GetOrderByQR(orderID);
Assert.AreEqual(HttpStatusCode.OK, testResponse.StatusCode);
}
While I was searching for an answer, I saw that the solution lies on mocking this authorization attribute. So, although I install this Moq package, couldn't achive to run as successful test as I'm new on unit testing.
Below is IdentityToken() method if you need to check it out also.
public User IdentifyToken(ClaimsIdentity identity)
{
string userEmail = "";
string userPassword = "";
if (identity != null)
{
IEnumerable<Claim> claims = identity.Claims;
List<Claim> claimsArray = claims.ToList();
string[] emailArray = claimsArray[0].ToString().Split(':');
string emailValue = emailArray[2].ToString();
userEmail = emailValue.Trim();
string[] passwordArray = claimsArray[1].ToString().Split(':');
string passwordValue = passwordArray[2].ToString();
userPassword = passwordValue.Trim();
}
var user = base.GetSingleBy(x => x.Email == userEmail && x.Password == userPassword);
return user;
}
How should I write my test method? Thank you in advance!
Edit:
Manager class instances are as below.
public class OrderController : BaseController
{
OrderManager _orderManager;
public OrderController()
{
_orderManager = new OrderManager();
}
//Order Controllers
}
you can use TestServer to test your API methods
using (var server = TestServer.Create<Startup>())
{
var result = await server.HttpClient.GetAsync("api/Orders/id");
string responseContent = await result.Content.ReadAsStringAsync();
var entity = JsonConvert.DeserializeObject<List<Orders>>(responseContent);
// other code
}
After spending another day to learn more about Unit Test, I found out that I need to treat (test in other word) each method seperately. If I'm not mistaken, that is also the point where Unit Test name is coming from.
So, first of all, I test this UserManager().IdentifyToken(identity); method of mine as below.
[TestMethod]
public void IdentifyToken_Returns_UserWM_On_Successful_Request()
{
UserManager userManager = new UserManager();
MD5Hasher passwordHasher = new MD5Hasher();
IEnumerable<Claim> claims = new List<Claim>
{
new Claim(ClaimTypes.Email, "creditmaster#admin.com"),
new Claim(ClaimTypes.Hash, passwordHasher.Encrypt("qW12345?"))
};
ClaimsIdentity identity = new ClaimsIdentity();
identity.AddClaims(claims);
var testResult = userManager.IdentifyToken(identity);
Assert.AreEqual(typeof(UserWM), testResult.GetType());
}
After receiving a successful test response, I carry on with _orderManager.GetSingleOrderWithUserPaymentAccountBy(user.UserID, id)); as shown below.
[TestMethod]
public void GetSingleOrderWithUserPaymentAccountBy_Returns_OrderWM_On_Successful_Request()
{
Random rnd = new Random();
int randomUser = rnd.Next(0, 690);
int randomOrder = rnd.Next(0, 40);
OrderManager orderManager = new OrderManager();
UserManager userManager = new UserManager();
List<UserWM> userList = userManager.GetAllUser();
var user = userList[randomUser];
List<OrderWM> orderList = orderManager.GetAllOrder();
var order = orderList[randomOrder];
string orderCode = "HHBI5OBFWG5WDSKP";
var testResult = orderManager.GetSingleOrderWithUserPaymentAccountBy(user.UserID, orderCode);
Assert.AreEqual(typeof(OrderWM), testResult.GetType());
}
In the end, if you could successfully unit test all your methods seperately, then they would work successfully when they are called simultaneously..
I also like to share below test method where I unit test my method (name is InsertUser) which insert users to database after all mandatory properties related with user entity filled as intended.
Tricky part is, this InsertUser contains too many if-else validation controls, such as,
if (string.IsNullOrEmpty(user.FirstName))
{
throw new BusinessException(JsonResponse.CreateBusinessExceptionResponse(ErrorMessageConstants.UserFirstnameEmptyError), "");
}
As there is too much code lines being talked about here, I do not want you to get lost around them, thus not sharing the whole Insert User.
If you have also run into a similar case in your unit tests, the only thing you should do is to gather these validations into another method (I named it InsertUserValidation). So, now we have two different methods: InsertUser and InsertUserValidation.
Now maybe you are asking why do we have to split validations from the main method. In my case, I have time dependent validations like below.
if (activationRequest == null)
{
throw new BusinessException(JsonResponse.CreateBusinessExceptionResponse(ErrorMessageConstants.UserActivationCodeNotRequested), "");
}
else if (activationRequest.CreationTime.AddMinutes(3) < DateTime.Now)
{
throw new BusinessException(JsonResponse.CreateBusinessExceptionResponse(ErrorMessageConstants.UserActivationCodeIsTimedOut), "");
}
Think about it, as time period between two Unit Test is unclear, you need to put these kind of validations into a different method, so you can mock them as described in below test method. For example, maybe I run my related method which creates that activationRequest five minutes ago, and I run my InsertUser method now. If I did't seperate this validation, InsertUser would still contain that above validation and it is going to throw exception as it is already more than three minutes when called.
[TestMethod]
public void InsertUser_Returns_UserWM_On_Successful_Request()
{
UserManager userManager = new UserManager();
MD5Hasher passwordHasher = new MD5Hasher();
Random rnd = new Random();
int dummyEmailName = rnd.Next(0, 700);
string dummyEmail = dummyEmailName.ToString() + "#gmail.com";
UserActivationRequest userActivationRequest = new UserActivationRequest
{
EMail = dummyEmail,
ActivationCode = "444855",
IsUsed = false,
IsActive = true,
ConfirmationType = 1,
ReadCount = 0
};
UserCreateAccountWM userCreateAccountWM = new UserCreateAccountWM()
{
FirstName = "Unit",
LastName = "Test",
Email = dummyEmail,
Password = passwordHasher.Encrypt("yC123456?"),
CountryID = 1,
PhoneCountryCode = 90,
MobileNumber = "5327894512",
ActivationCode = "444855"
};
var validationMock = new Mock<UserManager>();
validationMock.CallBase = true;
validationMock.Setup(x => x.InsertUserValidation(It.IsAny<UserCreateAccountWM>())).Returns(userActivationRequest); //if your validations do not return anything back, just forget about the part with .Returns()
var testResult = validationMock.Object.InsertUser(userCreateAccountWM);
Assert.AreEqual(typeof(UserWM), testResult.GetType());
}
Yes, if I'm not mistaken, you still need to create related entities.
Before I finish, I used Moq framework, and don't forget that methods you are seperating should be still under the same namespace.
Hope I would be helpful to those who are new to all these.
I have a functioning test but I need guidance how to properly test the logic. My understanding of testing is that it should be done without tight coupling to the resources (which is where mocking comes in) but if everything is mocked (especially the return result) how can the logic be tested, properly, without instantiating a bunch of classes?
ValidateEmployeeConfigurationAsync (below) will return RulesValidationResult which is what I want to assert. So I can answer my own question of how, which would require newing up repositories and services - that's one way. Is there a best practice way to accomplish that? That feels wrong.
Functioning Test
[TestMethod]
public async Task PassValidateEmployeeConfigurationTest()
{
//ARRANGE
const long employeeId = 200L;
const int configurationTypeId = (int) Constants.Configuration.ConfigurationTypes.User;
const bool enabled = true;
_ruleService = new Mock<IRuleService>();
_configurationService = new Mock<IConfigurationService>();
_ruleFacade = new Mock<IRuleFacade>();
_configurationService.Setup(x => x.GetByConfigurationNameAsync(It.IsAny<string>()))
.ReturnsAsync(GetConfigurations(enabled));
_ruleService.Setup(x => x.GetConfigRulesByEmployeeIdAsync(It.IsAny<long>()))
.ReturnsAsync(GetRules(enabled));
_ruleFacade.Setup(x =>
x.ValidateEmployeeConfigurationAsync(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<int>()))
.ReturnsAsync(GetPassedValidationResult());
//ACT
var result = await
_ruleFacade.Object.ValidateEmployeeConfigurationAsync(employeeId, "TestConfiguration", configurationTypeId);
//ASSERT
Assert.IsNotNull(result);
Assert.AreEqual(true, result.PassedValidation);
}
Method of interest
public async Task<RulesValidationResult> ValidateEmployeeConfigurationAsync(long employeeId, string configurationName, int configurationTypeId = 6)
{
var key = GetDefaultKey(configurationName);
var rules = new List<Rule>();
var validationResult = new RulesValidationResult();
validationResult.Messages.Add("Configuartion not found", configurationName);
var configurations = await _configurationService.GetByConfigurationNameAsync(configurationName);
if (!configurations.Any())
return validationResult;
var configuration = configurations.FirstOrDefault(c => c.ConfigurationTypeId == configurationTypeId);
rules = await _ruleService.GetConfigRulesByEmployeeIdAsync(employeeId);
if (rules.Any() && configuration.ConfigurationSettings.Any())
{
var testTargets = new List<ConfigurationSetting>();
testTargets.AddRange(from setting in configuration.ConfigurationSettings
where setting.IsActive && setting.Key == key
select new ConfigurationSetting
{
ConfigurationId = setting.ConfigurationId,
Key = setting.Key,
Value = setting.Value
});
if (PassesRules(testTargets, rules))
{
var msg = $"{configurationName} passed rule validation";
validationResult.PassedValidation = true;
validationResult.Messages.Clear();
validationResult.Messages.Add("Passed", msg);
}
else
{
var msg = $"{configurationName} failed rule validation";
validationResult.Messages.Clear();
validationResult.Messages.Add("Failed", msg);
}
}
return validationResult;
}
This is how I structured the test, view the previous version of the TestMethod to see the differences. In the original question, the test would always pass given the incorrect way the test was structured.
In this version, the input is mocked, the dependencies are mocked, and the IOC container is setup so the targeted code is tested and the assertion can be applied to the generated output.
[TestMethod]
public async Task PassValidateEmployeeConfigurationTest()
{
//ARRANGE
const long employeeId = 200L;
const int configurationTypeId = (int) Constants.Configuration.ConfigurationTypes.User;
//need the IOC container
var unityContainer = new UnityContainer();
//Mock ALL the dependencies (services and repositories)
var ruleFacade = new Mock<IRuleFacade>();
var employeeConfigMapRepo = new Mock<IEmployeeConfigurationMapRepo>();
var ruleRepo = new Mock<IRuleRepo>();
var ruleService = new Mock<IRuleService>();
var configurationService = new Mock<IConfigurationService>();
var employeeConfigurationService = new Mock<IEmployeeConfigurationService>();
var organizationConfigurationService = new Mock<IOrganizationConfigurationService>();
var facilityConfigurationService = new Mock<IFacilityConfigurationService>();
var configurationSettingService = new Mock<IConfigurationSettingService>();
// configure the dependencies so that the proper inputs are available
configurationService.Setup(x => x.GetByConfigurationNameAsync(It.IsAny<string>()))
.ReturnsAsync(GetConfigurations(true));
employeeConfigMapRepo.Setup(x => x.GetAllByEmployeeIdAsync(It.IsAny<int>()))
.ReturnsAsync(GetEmployeeConfigMaps(true));
employeeConfigurationService.Setup(x => x.GetAllByEmployeeIdAsync(It.IsAny<long>()))
.ReturnsAsync(GetEmployeeConfigMaps(true));
ruleRepo.Setup(x => x.GetByConfigurationIdAsync(It.IsAny<int>()))
.ReturnsAsync(GetRules(true));
ruleService.Setup(x => x.GetConfigRulesByEmployeeIdAsync(It.IsAny<long>(), It.IsAny<string>()))
.ReturnsAsync(GetRules(true));
// help the IOC do its thing, map interfaces to Mocked objects
unityContainer.RegisterInstance<IRuleService>(ruleService.Object);
unityContainer.RegisterInstance<IRuleRepo>(ruleRepo.Object);
unityContainer.RegisterInstance<IConfigurationService>(configurationService.Object);
unityContainer.RegisterInstance<IEmployeeConfigurationService>(employeeConfigurationService.Object);
unityContainer.RegisterInstance<IOrganizationConfigurationService>(organizationConfigurationService.Object);
unityContainer.RegisterInstance<IFacilityConfigurationService>(facilityConfigurationService.Object);
unityContainer.RegisterInstance<IConfigurationSettingService>(configurationSettingService.Object);
unityContainer.RegisterInstance<IRuleFacade>(ruleFacade.Object);
// thanks to all the mocking, the facade method ValidateEmployeeConfigurationAsync can now be tested properly
var ruleHelper = unityContainer.Resolve<RuleFacade>();
//ACT
var result = await
ruleHelper.ValidateEmployeeConfigurationAsync(employeeId, _testConfigName, configurationTypeId);
//ASSERT
Assert.IsNotNull(result);
Assert.AreEqual(true, result.PassedValidation);
}
This is a method under my controller which is used to create dummy keys to encrypt the data in the application and store the same in the amazon s3 bucket.
public JsonResult SaveMasterKeys(string MekText, int Thismek)
{
string folderName = string.Empty, fileName = string.Empty;
List<string> folderNameList = new List<string>();
folderNameList.Add("Guard1");
folderNameList.Add("Guard2");
try
{
if (Thismek == 1)
{
folderName = "Guard1";
fileName = "NewMek1.key";
}
else
{
folderName = "Guard2";
fileName = "NewMek2.key";
}
AWSS3File aws = new AWSS3File();
//aws.BucketExist(filePath);
//aws.CreateFile(MekText, filePath);
// Check Weather the Folder is exist or not
if (!aws.CheckFolderExist(folderName))
{
foreach (var item in folderNameList)
{
aws.CreateFolder(item);
if (item == "Guard1")
{
aws.CreateFileIntoS3((item == folderName ? MekText : ""), item, "NewMek1.key");
aws.CreateFileIntoS3("", item, "Mek1.key");
}
else
{
aws.CreateFileIntoS3((item == folderName ? MekText : ""), item, "NewMek2.key");
aws.CreateFileIntoS3("", item, "Mek2.key");
}
}
}
else
{
aws.CreateFileIntoS3(MekText, folderName, fileName);
}
ViewData["SaveMessage"] = "Saved successfully.";
}
catch (Exception ex)
{
XTP.Logger.LogCritical("XTP.Web.internaltools", ex.ToString());
ViewData["SaveMessage"] = "Keys not updated successfully.";
}
return Json(new { success = true, value = ViewData["SaveMessage"] }, JsonRequestBehavior.AllowGet);
}
And this is the TESTMETHOD I have written for the same
[TestMethod]
public void MockAlways()
{
var mock = new Mock<AccountController>();
JsonResult json = new JsonResult();
//new { success = true, value = ViewData["SaveMessage"] }, JsonRequestBehavior.AllowGet
json.Data = new { success = true, value = "sa" };
json.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
mock.Setup(x => x.SaveMasterKeys("ss", 1)).Returns(json);
var controller = new AccountController();
var result = controller.SaveMasterKeys("ss", 1) as JsonResult;
Assert.AreEqual(mock.Object.SaveMasterKeys("ssxs", 1), result.Data.ToString());
}
I am getting an invalid setup error. Is there a way to resolve this error?
I think that you misunderstood how to mock a controller's action. You are mocking it and then comparing it with the mocked controller. This is not a way to go(it is like checking whether true == true.
Basically this error means that Moq cannot override non-virtual member(it is self-explanatory). You should change method's signature to virtual to allow overriding it.
But - you shouldn't mock action like this. Instead you should mock its dependencies(services, contexts, gateways etc.) and check whether with known input values you can get expected results without mocking the action itself.
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.