How to properly test .net service logic - c#

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);
}

Related

How to write unit test for a MediatR handler C#

I'm trying to write unit test using Moq framework for one of my MediatR handler. I have the following code. Briefly, what this handler does is that it queries for the given key and returns a response that contains key and its value using EF Core. Also there is a basic cache mechanism. If the key found in cache it is pulled from cache and returned.
Handler
public GetConfigByKeyRequestHandler(MyContext context, ICacheProvider cacheProvider, IOptions<CacheConfigs> cacheConfigs)
{
this.context = context;
this.cacheProvider = cacheProvider;
this.cacheConfigs = cacheConfigs?.Value;
}
public async Task<ConfigResponse> Handle(GetConfigByKeyRequest request, CancellationToken cancellationToken)
{
ConfigResponse config;
if (!await cacheProvider.ExistsAsync(request.Key))
{
config = await context.Configs
.Where(x.ConfigKey.Equals(request.Key))
.Select(x =>
new ConfigResponse {
ConfigKey = x.ConfigKey,
ConfigValue = x.ConfigValue
})
.FirstOrDefaultAsync(cancellationToken);
if (config is not null)
{
await cacheProvider.PutAsync(new CacheItem<ConfigResponse>(request.Key, config), new CacheOptions
{
ExpireAfter = TimeSpan.FromMinutes(cacheConfigs.ExpireAfterInMinutes).TotalMilliseconds,
ExpireInactive = TimeSpan.FromMinutes(cacheConfigs.ExpireInActiveInMinutes).TotalMilliseconds
});
}
return config;
}
config = await cacheProvider.PullAsync<ConfigResponse>(request.Key);
return config;
}
I have thought that I should cover 2 different scenarios:
When the key found in the cache
When the key is not found in cache and it's returned from DbContext.
Unit tests
private Mock<ICacheProvider> cacheProviderMock;
private IOptions<CacheConfigs> cacheConfigs;
public GetConfigByKeyRequestHandlerTests()
{
cacheProviderMock = new Mock<ICacheProvider>();
cacheConfigs = Options.Create(
new CacheConfigs
{
ExpireAfterInMinutes = 3,
ExpireInActiveInMinutes = 3
});
}
[Fact]
public async Task GetConfigByKeyHandler_WhenKeyIsCached_ShouldReturnConfigByKey()
{
// arrange
var options = new DbContextOptionsBuilder<MyContext>().UseInMemoryDatabase("MyInMemoryDatabase").Options;
var configItems = Enumerable.Range(0, 5).Select(x => new Config
{
ConfigKey = $"key{x}",
ConfigValue = $"value{x}"
});
using (var context = new MyContext(options))
{
await context.Configs.AddRangeAsync(configItems);
await context.SaveChangesAsync();
}
using (var context = new MyContext(options))
{
cacheProviderMock.Setup(x => x.ExistsAsync(It.IsAny<string>())).Returns(Task.FromResult(true));
cacheProviderMock.Setup(x => x.PullAsync<ConfigResponse>("key2"))
.Returns(Task.FromResult(new ConfigResponse
{
ConfigKey = "key2",
ConfigValue = "value2"
}));
var getConfigByKeyHandler = new GetConfigByKeyRequestHandler(context, cacheProviderMock.Object, cacheConfigs);
var getConfigByKeyRequest = new GetConfigByKeyRequest("key2");
// act
var result = await getConfigByKeyHandler.Handle(getConfigByKeyRequest, CancellationToken.None);
// assert
Assert.NotNull(result);
Assert.Equal("key2", result.ConfigKey);
}
}
...
...
With the same logic, I have one more test for the other scenario that when key is not cached
...
...
[Fact]
public async Task GetConfigByKeyHandler_WhenKeyIsNotCached_ShouldReturnConfigByKey()
{
// arrange
var options = new DbContextOptionsBuilder<MyContext>().UseInMemoryDatabase("MyInMemoryDatabase").Options;
var configItems = Enumerable.Range(0, 5).Select(x => new Config
{
ConfigKey = $"key{x}",
ConfigValue = $"value{x}"
});
using (var context = new MyContext(options))
{
await context.Configs.AddRangeAsync(configItems);
await context.SaveChangesAsync();
}
using (var context = new MyContext(options))
{
cacheProviderMock.Setup(x => x.ExistsAsync(It.IsAny<string>())).Returns(Task.FromResult(false));
var getConfigByKeyHandler = new GetConfigByKeyRequestHandler(context, cacheProviderMock.Object, cacheConfigs);
var getConfigByKeyRequest = new GetConfigByKeyRequest("key2");
// act
var result = await getConfigByKeyHandler.Handle(getConfigByKeyRequest, CancellationToken.None);
// assert
Assert.NotNull(result);
Assert.Equal("key2", result.ConfigKey);
}
}
I have written 2 unit tests that covers the scenarios that I have mentioned above, but I'm not sure that they are reasonable ones and I'm not sure it should be tested like this way. Do you have any suggestions what/how should I write tests for the handler I shared above?

How to mock Azure Queue storage for unit test?

I want to mock QueueMessage for unit test,but I can not find any lib to mock
public async Task<QueueMessage[]> ReceiveMessagesAsync(QueueClient queue)
{
QueueProperties properties = queue.GetProperties();
// Retrieve the cached approximate message count.
int cachedMessagesCount = properties.ApproximateMessagesCount;
QueueMessage[] queueMessages =new QueueMessage[cachedMessagesCount];
int num = cachedMessagesCount / 32;
for (int i = 0; i < num + 1; i++)
{
var messages = await queue.ReceiveMessagesAsync(maxMessages: 32);
messages.Value.CopyTo(queueMessages,i*32);
}
return queueMessages;
}
Choice of Mocking lib would be an opinionated answer. There are several mocking frameworks available. One of the popular ones is Moq.
Using Moq, the sample test for your above code would look like below. Note that mocking storage lib is a bit tedious task as you can see.
[Test]
public async Task ReceiveMessagesAsync_StateUnderTest_ExpectedBehavior()
{
// Arrange
var queueClientHelper = new QueueClientHelper();
var queueMock = new Mock<QueueClient>();
var mockPropertiesResponse = new Mock<Response<QueueProperties>>();
var properties = new QueueProperties();
properties.GetType().GetProperty(nameof(properties.ApproximateMessagesCount), BindingFlags.Public | BindingFlags.Instance).SetValue(properties, 64); // little hack since ApproximateMessagesCount has internal setter
mockPropertiesResponse.SetupGet(r => r.Value).Returns(properties);
queueMock.Setup(q => q.GetProperties(It.IsAny<CancellationToken>())).Returns(mockPropertiesResponse.Object);
var mockMessageReponse = new Mock<Response<QueueMessage[]>>();
mockMessageReponse.SetupGet(m => m.Value).Returns(new QueueMessage[32]);
queueMock.Setup(q => q.ReceiveMessagesAsync(It.IsAny<int?>(), It.IsAny<TimeSpan?>(), It.IsAny<CancellationToken>())).ReturnsAsync(mockMessageReponse.Object);
// Act
var result = await queueClientHelper.ReceiveMessagesAsync(queueMock.Object);
// Assert
Assert.AreEqual(64, result.Length);
// verify mocks as required
}
The constructors of the Queue models are internal, but you can create objects using the QueuesModelFactory which provides utilities for mocking.
QueueMessage queueMsg = QueuesModelFactory.QueueMessage(
messageId: "id2",
popReceipt: "pr2",
body: JsonConvert.SerializeObject("Test"),
dequeueCount: 1,
insertedOn: DateTimeOffset.UtcNow);
var metadata = new Dictionary<string, string> { { "key", "value" }, };
int messageCount = 5;
QueueProperties queueProp = QueuesModelFactory.QueueProperties(metadata, messageCount);
Try to mock the response of queueClient this will verify sendMessageAsync response
[Fact]
public async Task SendMessage_ShouldReturnSuccess()
{
var receipt = QueuesModelFactory.SendReceipt("1", DateTimeOffset.Now, DateTimeOffset.Now.AddDays(2), "pop", DateTimeOffset.Now.AddDays(1));
var res = Response.FromValue<SendReceipt>(receipt, null);
var queueClientmock = new Mock<QueueClient>();
queueClientmock.Setup(q => q.SendMessageAsync(It.IsAny<string>())).Returns(Task.FromResult(res));
var sqmock = new Mock<IStorageQueueProvider>();
sqmock.Setup(s => s.GetStorageQueueClient()).Returns(Task.FromResult(queueClientmock.Object)).Verifiable();
var storageQueueRepository = new StorageQueueRepository(sqmock.Object, DummyLogger);
var result = await storageQueueRepository.SendMessage("test message");
result.StatusCode.Should().Be(HttpStatusCode.OK);
}
return QueuesModelFactory.QueueMessage(
messageId: "id2",
popReceipt: "pr2",
body: BinaryData.FromString(encode ? Convert.ToBase64String(Encoding.UTF8.GetBytes(Message)) : Message),
dequeueCount: dequeueCount,
insertedOn: DateTimeOffset.UtcNow);

How to properly setup mock data for unit test?

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)

How to test for exception in Nest?

I am trying to test for the results of certain exceptions when Nest has a value in IGetResponse.OriginalException property.
I first set up the response:
var response = A.Fake<Nest.IGetResponse<Dictionary<string, object>>>();
A.CallTo(() => response.OriginalException).Returns(new Exception("Status code 404"));
Then the fake elastic client:
var client = A.Fake<Nest.IElasticClient>();
A.CallTo(client)
.WithReturnType<Nest.IGetResponse<Dictionary<string, object>>>()
.Returns(response);
The client gets injected into the class I am testing.
However, when stepping through the code, when the client is called it returns a faked response, but the OriginalException getter has no value. Its not null, but none of the properties has any value. I was expecting the OriginalException.Message to equal Status code 404.
I also tried setting the response object to:
var response = A.Fake<Nest.IGetResponse<Dictionary<string, object>>>();
A.CallTo(() => response.OriginalException.Message).Returns("Status code 404");
... with equally poor results.
How can I set the IGetResponse so I can evaluate OriginalException.Message in the class being tested?
More code was requested. I can show the entire test, and I will show the method being tested. Here is my entire test:
[TestMethod]
[ExpectedException(typeof(NotFoundException))]
public void Get_ClientReturns404_ThrowsNotFoundException()
{
// setup
var request = new DataGetRequest
{
CollectionName = string.Empty,
DocumentType = string.Empty,
DataAccessType = string.Empty
};
var response = A.Fake<Nest.IGetResponse<Dictionary<string, object>>>();
A.CallTo(() => response.OriginalException.Message).Returns("Status code 404");
var client = A.Fake<Nest.IElasticClient>();
A.CallTo(client)
.WithReturnType<Nest.IGetResponse<Dictionary<string, object>>>()
.Returns(response);
var elasticSearch = new ElasticSearch(null, client);
// test
var result = elasticSearch.Get(request);
// assert
Assert.Fail("Should have hit an exception.");
}
}
And here is the method being tested:
public async Task<Dictionary<string, object>> Get(DataGetRequest getRequest)
{
GetRequest request = new GetRequest(getRequest.CollectionName, getRequest.DocumentType, getRequest.Id);
var response = await Client.GetAsync<Dictionary<string, object>>(request);
if (response.OriginalException != null)
{
var message = response.OriginalException.Message;
if (message.Contains("Status code 404"))
throw new NotFoundException(String.Format("Not Found for id {0}", getRequest.Id));
else
throw new Exception(message);
}
return response.Source;
}
The error handling in the IF block is not very robust. Once the unit test works then the code will likely receive more love.
The return type of the mocked client is wrong as the IElasticClient.GetAsync<> returns a Task<IGetResponse<T>>.
Task<IGetResponse<T>> GetAsync<T>(IGetRequest request, CancellationToken cancellationToken = default(CancellationToken)) where T : class;
Source
So the setup needs to return a Task derived result to allow the async code
var response = await Client.GetAsync<Dictionary<string, object>>(request);
to flow as expected.
For example
[TestMethod]
[ExpectedException(typeof(NotFoundException))]
public async Task Get_ClientReturns404_ThrowsNotFoundException() {
//Arrange
var originalException = new Exception("Status code 404");
var response = A.Fake<Nest.IGetResponse<Dictionary<string, object>>>();
A.CallTo(() => response.OriginalException).Returns(originalException);
var client = A.Fake<Nest.IElasticClient>();
A.CallTo(() =>
client.GetAsync<Dictionary<string, object>>(A<IGetRequest>._, A<CancellationToken>._)
).Returns(Task.FromResult(response));
var request = new DataGetRequest {
CollectionName = string.Empty,
DocumentType = string.Empty,
DataAccessType = string.Empty
};
var elasticSearch = new ElasticSearch(null, client);
// Act
var result = await elasticSearch.Get(request);
// Assert
Assert.Fail("Should have hit an exception.");
}

Unit Testing a Web API controller which Has Been Authorized with JWT

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.

Categories