I have a service name "DataAccessService". In that service we are calling Procedure and other methods from AppDbContext.
I am writing Unit Test cases for DataAccessService methods. We have method called IsDatabaseUp() which will give response if connection with databases success or not.
When I am trying to access AppDbContext is null which is breaking the unit test method.
DataAccessService:
public bool IsDatabaseUp()
{
try
{
int counter = 1;
while (counter <= EnvConstants.DatabaseCounter)
{
try
{
using (var scope = _serviceScopeFactory.CreateScope())
{
AppDbContext dbContext = scope.ServiceProvider.GetService<AppDbContext>();
//Here dbContext is null
bool isDbUp = dbContext.IsDatabaseUp;
if (isDbUp)
return isDbUp;
counter++;
}
}
catch (Exception ex)
{
counter++;
}
}
}
catch (Exception ex)
{
}
return false;
}
DataServiceTests:
private readonly IDataAccessService _dataAccessService;
private readonly Mock<IServiceScopeFactory> _serviceScopeFactory;
public DataAccessServiceTest()
{
//Arrange
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider
.Setup(x => x.GetService(typeof(AppDbContext)));
var serviceScope = new Mock<IServiceScope>();
serviceScope.Setup(x => x.ServiceProvider).Returns(serviceProvider.Object);
_serviceScopeFactory = new Mock<IServiceScopeFactory>();
_serviceScopeFactory
.Setup(x => x.CreateScope())
.Returns(serviceScope.Object);
serviceProvider
.Setup(x => x.GetService(typeof(IServiceScopeFactory)))
.Returns(_serviceScopeFactory.Object);
var serviceCollection = new ServiceCollection();
serviceCollection.AddMemoryCache();
var serviceProvider1 = serviceCollection.BuildServiceProvider();
var memoryCache = serviceProvider1.GetService<IMemoryCache>();
var inMemoryCahce= new InMemoryCahce(memoryCache);
_dataAccessService = new DataAccessService(_serviceScopeFactory.Object);
_cacheService = new ServiceOfCahe(inMemoryCahce, _dataAccessService);
LoadMemoryData();
}
[Fact]
public void GetMasterDataInfromationFromSql_Test()
{
var testResult = _dataAccessService.IsDatabaseUp();
}
Can you please help me on this.
At the time of the user's connection, everything is going well. When I have a product update (it becomes available for sale), the OnProductStartSales event is called.
But there is one problem, the message does not come to the client because the list of clients in the hub is disposed.
Here is the code of my hub.
public class SalesHub : Hub
{
private readonly ProductDatabaseListener _listener;
public SalesHub(ProductDatabaseListener listener)
{
_listener = listener ?? throw new ArgumentNullException(nameof(listener));
_listener.OnProductStartSales += (s, p) => ProductStartSales(p);
_listener.OnProductDataChanged += (s, p) => ProductDataChanged(p);
}
public async Task ListenProduct(string productId)
{
await this.Groups.AddToGroupAsync(Context.ConnectionId, productId);
}
private async Task ProductStartSales(Product product)
{
await this.Clients.Group(product.Id).SendAsync("StartSales", product.Id);
// await this.Clients.All.SendAsync("StartSales", product.Id);
}
private async Task ProductDataChanged(Product product)
{
await this.Clients.Group(product.Id).SendAsync("DataChanged", product);
}
}
Here is the code of listener.
public class ProductDatabaseListener
{
private readonly IRepository<Product> _repository;
private readonly object _locker = new object();
public ProductDatabaseListener(IServiceProvider serviceProvider)
{
using (var scope = serviceProvider.CreateScope())
{
_repository = scope.ServiceProvider.GetRequiredService<IRepository<Product>>() ?? throw new ArgumentNullException(nameof(_repository));
}
}
public event EventHandler<Product> OnProductStartSales;
public event EventHandler<Product> OnProductDataChanged;
// Need better performance...
public async Task ListenMongo()
{
while (true)
{
var products = await _repository.GetRange(0, int.MaxValue);
var date = DateTime.Now;
List<Task> tasks = new List<Task>();
foreach (var product in products)
{
if (product.IsSalesStart)
{
continue;
}
if (product.StartOfSales <= date)
{
product.IsSalesStart = true;
OnProductStartSales?.Invoke(this, product);
tasks.Add(_repository.Update(product));
}
}
Task.WaitAll(tasks.ToArray());
await Task.Delay(1000);
}
}
}
Here is the client code
"use strict";
var connection = new signalR.HubConnectionBuilder().withUrl("/salesHub").build();
connection.on("ReceiveMessage", function (id) {
var li = document.createElement("li")
document.getElementById("fromHub").appendChild(li)
li.textContent = id;
});
connection.on("startSales", function (id) {
var productId = document.getElementById("objectId").getAttribute("value");
if (productId == id) {
var button = document.getElementById("buy")
button.hidden = false
}
});
connection.logging = true;
connection.start().then(function () {
var productId = document.getElementById("objectId").getAttribute("value");
connection.invoke("ListenProduct", productId).catch(function (err) {
return console.error(err.toString());
});
event.preventDefault();
}).catch(function (err) {
return console.error(err.toString());
});
I'm trying to write an Unit Test for my ASP.Net Core application with XUnit framework and MOQ and am trying to test the below method(snippet given below):
public async Task<IActionResult> Save([FromBody] DTO.ContactUs contactUs)
{
contactUs.FirstName = _htmlEncoder.Encode(contactUs.FirstName);
contactUs.LastName = _htmlEncoder.Encode(contactUs.LastName);
contactUs.EmailAddress = _htmlEncoder.Encode(contactUs.EmailAddress);
contactUs.Phone = _htmlEncoder.Encode(contactUs.Phone);
if (HttpContext.User.CurrentClient() != null)
contactUs.ClientId = HttpContext.User.CurrentClient().ClientId;
contactUs.UserId = User.GetUserId();
string dbName = HttpContext.User.CurrentClient().ConnectionString;
var result = _clientService.AddNewContactUs(contactUs, dbName);
if (result)
{
try
{
int clientId = HttpContext.User.CurrentClient().ClientId;
var clientDetails = _clientService.GetClientDetailsByClientID(clientId);
// Lines of code...
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
return Json(result);
}
While I can mock all the other dependent services, I'm kind of stuck with the HttpContext part. I am not able to mock the HttpContext.User.CurrentClient() part where HttpContext.User is of type ClaimsPrincipal and CurrentClient is an user-defined function, defined as:
public static Client CurrentClient(this ClaimsPrincipal principal)
{
if (!string.IsNullOrEmpty(principal.Claims.Single(p => p.Type.Equals(AppClaimTypes.CurrentClient)).Value))
{
int clientId = Convert.ToInt32(principal.Claims.Single(p => p.Type.Equals(AppClaimTypes.CurrentClient)).Value);
return principal.GetClients().Where(c => c.ClientId == clientId).FirstOrDefault();
}
else
{
return null;
}
}
This is my UnitTest class that I have managed to write till now:
public class ContactUsControllerTests
{
private Mock<IClientService> clientServiceMock;
private Mock<IWebHostEnvironment> webHostEnvironmentMock;
private Mock<HtmlEncoder> htmlEncoderObjMock;
private Mock<IEmailNotification> emailNotificationMock;
private Mock<HttpContext> mockContext;
private Mock<HttpRequest> mockRequest;
private Mock<ClaimsPrincipal> mockClaimsPrincipal;
private ContactUs contactUsObj = new ContactUs()
{
FirstName = "TestFN",
LastName = "TestLN",
EmailAddress = "testemail#gmail.com",
Phone = "4564560000",
Comments = "This is just a test"
};
private ClaimsPrincipal principal = new ClaimsPrincipal();
public ContactUsControllerTests()
{
clientServiceMock = new Mock<IClientService>();
webHostEnvironmentMock = new Mock<IWebHostEnvironment>();
htmlEncoderObjMock = new Mock<HtmlEncoder>();
emailNotificationMock = new Mock<IEmailNotification>();
mockRequest = new Mock<HttpRequest>();
mockContext = new Mock<HttpContext>();
// set-up htmlEncoderMock
htmlEncoderObjMock.Setup(h => h.Encode(contactUsObj.FirstName)).Returns(contactUsObj.FirstName);
htmlEncoderObjMock.Setup(h => h.Encode(contactUsObj.LastName)).Returns(contactUsObj.LastName);
htmlEncoderObjMock.Setup(h => h.Encode(contactUsObj.EmailAddress)).Returns(contactUsObj.EmailAddress);
htmlEncoderObjMock.Setup(h => h.Encode(contactUsObj.Phone)).Returns(contactUsObj.Phone);
htmlEncoderObjMock.Setup(h => h.Encode(contactUsObj.Comments)).Returns(contactUsObj.Comments);
// set-up mockContext
mockContext.Setup(m => m.Request).Returns(mockRequest.Object);
mockContext.Object.User.CurrentClient().ClientId = 30; // this throws error
//other initialisations
}
[Fact]
public async void SaveMethodTest()
{
ContactUsController contactUsControllerObj = new ContactUsController(clientServiceMock.Object, webHostEnvironmentMock.Object, htmlEncoderObjMock.Object, emailNotificationMock.Object);
// Act
await contactUsControllerObj.Save(contactUsObj);
// Arrange
// Lines of code
}
}
Any help whatsoever on this would very helpful.
I'm writing a unit test where I'm trying to partially mock a service. What I mean is I want one of the methods of the service to return a different mocked object and another method to behave as normal. This is the method I'm testing:
public async Task<List<string>> GetDeletedRecordIds<T>(DateTime startDate)
where T : ISalesForceObject
{
List<string> result;
try
{
var client = await this.GetForceClient();
var init = await client.GetDeleted<DeletedRecordRootObject>(typeof(T).Name, startDate, DateTime.Now);
result = init?.DeletedRecords.Select(d => d.Id).ToList();
}
catch (Exception e)
{
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, "GetDeletedRecordIds");
throw;
}
return result;
}
This is the method that I need to return a mocked object:
public async Task<IForceClient> GetForceClient()
{
ForceClient forceClient = null;
try
{
var auth = new AuthenticationClient();
var consumerKey = this._settingService.GetSetting("SalesForceConsumerKey");
var consumerSecret = this._settingService.GetSetting("SalesForceConsumerSecret");
var password = this._settingService.GetSetting("SalesForcePassword");
var securityToken = this._settingService.GetSetting("SalesForceSecurityToken");
var username = this._settingService.GetSetting("SalesForceUsername");
var tokenUrl = $"{this._settingService.GetSetting("SalesForceUrl")}/services/oauth2/token";
await auth.UsernamePasswordAsync(
consumerKey,
consumerSecret,
username,
password + securityToken,
tokenUrl);
forceClient = new ForceClient(auth.InstanceUrl, auth.AccessToken, auth.ApiVersion);
}
catch (Exception e)
{
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, $"GetForceClient");
throw;
}
return forceClient;
}
And this is what I currently have in my unit test:
var mockForceClient = new Mock<IForceClient>();
mockForceClient
.Setup(
i => i.GetDeleted<DeletedRecordRootObject>(
It.IsAny<string>(),
It.IsAny<DateTime>(),
It.IsAny<DateTime>())).ReturnsAsync(deletedRecordRootObject);
var mockService = new Mock<IForceDotComService>();
mockService.Setup(m => m.GetDeletedRecordIds<sf.Account>(It.IsAny<DateTime>()))
.Returns(async (DateTime d) => await this._service.GetDeletedRecordIds<sf.Account>(d));
mockService.Setup(m => m.GetForceClient())
.ReturnsAsync(mockForceClient.Object);
Currently, the test runs in GetDeletedRecordIds until it hits the call to the GetForceClient method. Then instead of returning the mocked ForceClient object, it actually tries to run the method which of course fails.
Thanks in advance for any help.
SOLUTION:
Here's how I solved my problem.
First, I created a service to return the ForceClient as follows:
public class ForceClientService : IForceClientService
{
private readonly ILogger _logger;
private readonly ISettingService _settingService;
public ForceClientService(
ILogger<ForceClientService> logger,
ISettingService settingService)
{
this._logger = logger;
this._settingService = settingService;
}
public async Task<IForceClient> GetForceClient()
{
ForceClient forceClient = null;
try
{
var auth = new AuthenticationClient();
var consumerKey = this._settingService.GetSetting("SalesForceConsumerKey");
var consumerSecret = this._settingService.GetSetting("SalesForceConsumerSecret");
var password = this._settingService.GetSetting("SalesForcePassword");
var securityToken = this._settingService.GetSetting("SalesForceSecurityToken");
var username = this._settingService.GetSetting("SalesForceUsername");
var tokenUrl = $"{this._settingService.GetSetting("SalesForceUrl")}/services/oauth2/token";
await auth.UsernamePasswordAsync(
consumerKey,
consumerSecret,
username,
password + securityToken,
tokenUrl);
forceClient = new ForceClient(auth.InstanceUrl, auth.AccessToken, auth.ApiVersion);
}
catch (Exception e)
{
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, $"GetForceClient");
throw;
}
return forceClient;
}
}
Then I changed the method I am testing:
public async Task DeleteRecord<TSf>(TSf record)
where TSf : ISalesForceObject
{
try
{
var client = await this._forceClientService.GetForceClient();
var response = await client.DeleteAsync(typeof(TSf).Name, record.Id);
if (!response)
{
throw new Exception($"Error deleting record with ID {record.Id}");
}
}
catch (Exception e)
{
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, $"ForceDotComService.DeleteRecord");
throw;
}
}
Then I rebuilt my mock to mock the dependencies vs. the methods:
var mockForceClient = new Mock<IForceClient>();
mockForceClient
.Setup(
i => i.GetDeleted<DeletedRecordRootObject>(
It.IsAny<string>(),
It.IsAny<DateTime>(),
It.IsAny<DateTime>())).ReturnsAsync(deletedRecordRootObject);
var mockLogger = new Mock<ILogger<ForceDotComService>>();
var mockForceClientService = new Mock<IForceClientService>();
mockForceClientService.Setup(m => m.GetForceClient()).ReturnsAsync(mockForceClient.Object);
this._service = new ForceDotComService(mockLogger.Object, mockForceClientService.Object);
It is now working as expected. Thanks so much for the help!
Extract this.GetForceClient() out into its own service backed by an abstraction
public IForceClientProvider {
Task<IForceClient> GetForceClient();
}
you would then refactor your current class under test to explicitly depend on that interface via constructor injection.
public class ForceDotComService : IForceDotComService {
private readonly IForceClientProvider provider;
public ForceDotComService(IForceClientProvider provider) {
this.provider = provider;
}
public async Task<List<string>> GetDeletedRecordIds<T>(DateTime startDate)
where T : ISalesForceObject {
List<string> result;
try {
var client = await provider.GetForceClient();
var init = await client.GetDeleted<DeletedRecordRootObject>(typeof(T).Name, startDate, DateTime.Now);
result = init?.DeletedRecords.Select(d => d.Id).ToList();
} catch (Exception e) {
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, "GetDeletedRecordIds");
throw;
}
return result;
}
}
This would then allow you to mock the desired behavior when testing. In implementation code you would have the same code presented above in the GetForceClient() method.
You mock dependencies, not methods on the class under test.
You need to inject the dependency IForceClient, for example by making it a constructor parameter. Because now your GetForceClient() is simply being called on the class under test, which runs in that class and not on your mock, and so simply returns the new ForceClient() stated in there.
i'm trying to make a test in my example projet, and i'm getting an error when i assert if the deleted object is null(Assert.IsNull failed).
I'm using Microsoft Visual Studio 2010, Entity Framework 4.3.1 and regular Moq.
Here is the code i'm using:
Service:
private ClientRepository rep;
public ClientService(MyContext ctx)
{
this.rep = new ClientRepository(ctx);
}
public void Delete(Client client)
{
try
{
rep.Delete(client);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
throw new Exception("error");
}
}
public Client GetById(int Id)
{
return rep.GetById(Id);
}
Repository:
private MyContext _dbContext;
public ClientRepository(MyContext ctx)
{
_dbContext = ctx;
}
public void Delete(Client client)
{
Client cl = _dbContext.Clients.Where(x => x.Id == client.Id).FirstOrDefault();
if (cl != null)
{
_dbContext.Clients.Remove(client);
_dbContext.SaveChanges();
}
else
{
throw new Exception("Client does'n exist");
}
}
public Client GetById(int Id)
{
return _dbContext.Clients.Where(x => x.Id == Id).FirstOrDefault();
}
My Delete Test:
[TestMethod]
public void MockDelete()
{
//arrange
var data = new List<Client>
{
new Client(){
Id = 1,
Name = "asdfg"
}
}.AsQueryable();
var dbSetMock = new Mock<IDbSet<Client>>();
var myContextMock = new Mock<MyContext>();
dbSetMock.As<IQueryable<Client>>().Setup(m => m.Provider).Returns(data.Provider);
dbSetMock.As<IQueryable<Client>>().Setup(m => m.Expression).Returns(data.Expression);
dbSetMock.As<IQueryable<Client>>().Setup(m => m.ElementType).Returns(data.ElementType);
dbSetMock.As<IQueryable<Client>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
myContextMock.Setup(m => m.Clients).Returns(dbSetMock.Object);
var service = new ClientService(myContextMock.Object);
//act
var classtodelete = data.First(m => m.Id == 1);
service.Delete(classtodelete);
string name = service.GetById(1).Name;
//assert
dbSetMock.Verify(m => m.Remove(It.IsAny<Client>()), Times.Once());
myContextMock.Verify(m => m.SaveChanges(), Times.Once);
Assert.IsNull(name);
}
My goal is to test the business rules of my Service(i didn't put here), maybe i mocked the wrong classes, or i'm missing something, i hope someone can help me.