Unit test using moq to an api rest core - c#

I am doing an unit test with moq, mi code is about an api. I already done the service and repository, but i get error when i want to return the result.
I am new in moq and i can´t understand fine how it is the use with moq.
This is my repository
{
Task<List<Course>> FindAll();
Task<Course?> FindById(int id);
Task<List<Course>> FindByIds(List<int> ids);
void Insert(Course Course);
Task Delete(int id);
void Update(Course Course);
Task<int> Save();
}
This is my service
public class CourseService: ICourseService {
private readonly ICourseRepository _courseRepository;
private readonly IMapper _mapper;
private ICourseRepository #object;
private IMapper object1;
public CourseService(ICourseRepository courseRepository, IMapper mapper) {
_courseRepository = courseRepository;
_mapper = mapper;
}
public CourseService(ICourseRepository #object) {
this.#object = #object;
}
public CourseService(IMapper object1) {
this.object1 = object1;
}
public async Task < List < CourseDto >> FindAll() {
List < Course > course = await _courseRepository.FindAll();
return _mapper.Map < List < Course > , List < CourseDto >> (course);
}
public async Task < CourseDto ? > FindById(int id) {
Course ? course = await _courseRepository.FindById(id);
return course == null ? null : _mapper.Map < Course, CourseDto > (course);
}
}
}
This is my testing
public class CourseServiceTest {
private readonly CourseService _sut;
private readonly Mock < ICourseRepository > _courseRepoMock = new Mock < ICourseRepository > ();
private readonly Mock < IMapper > _mapperMock = new Mock < IMapper > ();
public CourseServiceTest() {
_sut = new CourseService(_courseRepoMock.Object);
//_sut = new CourseService(_mapperMock.Object);
}
[Fact]
public async Task GetAllCoursesById() {
//Arrange
var courseId = 1;
var courseName = "Esta es una prueba";
var courseDescription = "Description";
var courseDuration = 34.5;
var courseRating = 34.5;
var courseDeleted = false;
var courseCreatedBy = 1;
var courseUpdatedBy = 1;
var courseDto = new CourseDto {
Name = courseName,
Description = courseDescription,
Duration = courseDuration,
Rating = courseRating,
Deleted = courseDeleted,
CreatedBy = courseCreatedBy,
UpdatedBy = courseUpdatedBy
};
_courseRepoMock.Setup(x => x.FindById(courseId)).ReturnsAsync(CourseDto);
//Act
var course = await _sut.FindById(courseId);
//Assert
Assert.Equal(courseId, course.Id);
Assert.Equal(courseDescription, course.Description);
Assert.Equal(courseDuration, course.Duration);
Assert.Equal(courseRating, course.Rating);
Assert.Equal(courseDeleted, course.Deleted);
Assert.Equal(courseCreatedBy, course.CreatedBy);
Assert.Equal(courseUpdatedBy, course.UpdatedBy);
}
}
**I need the testing for the both methods, FindAll and FindById **

Related

C# xUnit test actual values returned are empty

I'm trying to write unit test using xUnit for EntityService class which is using Dapper to get data from Sqllite database. In my unit test it always returns actual values as List<Entity> [] and test fails. I'm not understanding what I am missing here.
Test Class
public class EntityServiceTests
{
private readonly IEntityService _sut;
private readonly Mock<IEntityService> _entityServiceMock;
public EntityServiceTests()
{
_entityServiceMock = new Mock<IEntityService>();
var dapperMock = new Mock<IDapperWrapper>();
_sut = new EntityService(dapperMock.Object);
}
[Fact]
public void GetEntities_ShouldReturnEntities()
{
//Arrange
var expectedEntities = new List<Entity>
{
new()
{
Id = 1,
Name = "Test",
X = 12,
Y = 14.5,
CoordId = 1
},
new()
{
Id = 2,
Name = "Test2",
X = 16,
Y = 18.5,
CoordId = 2
}
};
var query = #"SELECT ent.*, crd.x, crd.y, crd.id as CoordId
FROM entities ent
INNER JOIN coords crd ON crd.entityId = ent.Id";
_entityServiceMock.Setup(x => x.GetEntities(0)).Returns(expectedEntities);
//Act
var entities = _sut.GetEntities(0).ToList();
//Assert
Assert.Equal(expectedEntities, entities);
}
}
Service Class
public class EntityService : IEntityService
{
private readonly IDapperWrapper _dapperWrapper;
public EntityService(IDapperWrapper dapperWrapper)
{
_dapperWrapper = dapperWrapper;
}
public IEnumerable<Entity> GetEntities(int entityId)
{
var query = #"SELECT ent.*, crd.x, crd.y, crd.id as CoordId
FROM entities ent
INNER JOIN coords crd ON crd.entityId = ent.Id ";
if (entityId > 0)
{
query += " WHERE ent.id = #id";
var entities = _dapperWrapper.Query<Entity>(query, new { id = entityId });
return entities;
}
else
{
var entities = _dapperWrapper.Query<Entity>(query);
return entities;
}
}
}
Dapper Wrapper Class
public class DapperWrapper : IDapperWrapper
{
private IDbConnection Connection { get; }
public DapperWrapper()
{
Connection = new SQLiteConnection(GetConnectionString("ConnectionString"));
}
private string GetConnectionString(string name)
{
return ConfigurationManager.ConnectionStrings[name].ConnectionString;
}
public IEnumerable<T> Query<T>(string query)
{
return Connection.Query<T>(query);
}
public IEnumerable<T> Query<T>(string query, object param)
{
return Connection.Query<T>(query, param);
}
public T QuerySingle<T>(string query, object param)
{
return Connection.QuerySingle<T>(query, param);
}
}
Normally the project is working fine. but in Test it fails. I think i'm missing something very basic but crucial.
UPDATE: I'm using this code now but still getting failed result
[Fact]
public void GetEntities_Should_Return_All_Entities_If_0_Is_Provided_In_Param()
{
//Arrange
var expectedEntities = new List<Entity>
{
new()
{
Id = 1,
Name = "Test",
X = 12,
Y = 14.5,
CoordId = 1
},
new()
{
Id = 2,
Name = "Test2",
X = 16,
Y = 18.5,
CoordId = 2
}
};
var query = #"SELECT ent.*, crd.x, crd.y, crd.id as CoordId
FROM entities ent
INNER JOIN coords crd ON crd.entityId = ent.Id ";
var dapperMock = new Mock<IDapperWrapper>();
dapperMock.Setup(x => x.Query<Entity>(query)).Returns(expectedEntities);
var sut = new EntityService(dapperMock.Object);
//Act
var entities = sut.GetEntities(0);
//Assert
Assert.Equal(expectedEntities, entities);
}
I think i'm missing something very basic but crucial.
Indeed 🙂 mocking is intended to be used to mock away the dependencies from a unit to test (sut). In your case your unit to test is the EntityService and the dependency to mock away is IDapperWrapper.
But instead of only mocking the dependency, you're mocking the SUT as well with _entityServiceMock.
So you COULD try to do it like this within your test:
public class EntityServiceTests
{
[Fact]
public void GetEntities_ShouldReturnEntities()
{
//Arrange
var expectedEntities = new List<Entity>
{
new()
{
Id = 1,
Name = "Test",
X = 12,
Y = 14.5,
CoordId = 1
}
};
var query = #"SELECT ent.*, crd.x, crd.y, crd.id as CoordId
FROM entities ent
INNER JOIN coords crd ON crd.entityId = ent.Id WHERE ent.id = #id";
var dapperMock = new Mock<IDapperWrapper>();
dapperMock.Setup(x => x.Query<Entity>(query, 1)).Returns(expectedEntities.First());
var sut = new EntityService(dapperMock.Object);
//Act
var entities = sut.GetEntities(1).ToList();
//Assert
Assert.Equal(expectedEntities, entities);
}
}
But I highly discourage you from doing so because you'll end up mocking all the Dapper stuff.
Instead you better use an in-memory database (like SQLite), use a real Dapper instance. This way your tests will become much more comprehensive, shorter and business-facing. This blog post should give you a good starting point.

Unable to cast object of type 'System.Linq.EnumerableQuery` to type 'MongoDB.Driver.Linq.IMongoQueryable`

I have a class SendNotificationsToSubscribersCommandHandler with the following Method Handle and I have test method GetAllSubscriptionsWithCorrectParamsProductId() to check that Handle method returns correct List.
I get following error:
Message:
Test method Grand.Services.Tests.Commands.Handlers.Catalog.SendNotificationsToSubscribersCommandHandlerTest.GetAllSubscriptionsWithCorrectParamsProductId threw exception:
System.InvalidCastException: Unable to cast object of type 'System.Linq.EnumerableQuery`1[Grand.Domain.Catalog.BackInStockSubscription]' to type 'MongoDB.Driver.Linq.IMongoQueryable`1[Grand.Domain.Catalog.BackInStockSubscription]'.
Stack Trace:
MongoQueryable.Where[TSource](IMongoQueryable`1 source, Expression`1 predicate)
SendNotificationsToSubscribersCommandHandler
public class SendNotificationsToSubscribersCommandHandler : IRequestHandler<SendNotificationsToSubscribersCommand, IList<BackInStockSubscription>>
{
private readonly ICustomerService _customerService;
private readonly IWorkflowMessageService _workflowMessageService;
private readonly IRepository<BackInStockSubscription> _backInStockSubscriptionRepository;
public SendNotificationsToSubscribersCommandHandler(
ICustomerService customerService,
IWorkflowMessageService workflowMessageService,
IRepository<BackInStockSubscription> backInStockSubscriptionRepository)
{
_customerService = customerService;
_workflowMessageService = workflowMessageService;
_backInStockSubscriptionRepository = backInStockSubscriptionRepository;
}
public async Task<IList<BackInStockSubscription>> Handle(SendNotificationsToSubscribersCommand request, CancellationToken cancellationToken)
{
if (request.Product == null)
throw new ArgumentNullException("product");
int result = 0;
var query = _backInStockSubscriptionRepository.Table;
//product
query = query.Where(biss => biss.ProductId == request.Product.Id);
//warehouse
if (!string.IsNullOrEmpty(request.Warehouse))
query = query.Where(biss => biss.WarehouseId == request.Warehouse);
//warehouse
if (!string.IsNullOrEmpty(request.AttributeXml))
query = query.Where(biss => biss.AttributeXml == request.AttributeXml);
query = query.OrderByDescending(biss => biss.CreatedOnUtc);
var subscriptions = await query.ToListAsync();
//var subscriptions = await GetAllSubscriptionsByProductId(request.Product.Id, request.AttributeXml, request.Warehouse);
foreach (var subscription in subscriptions)
{
var customer = await _customerService.GetCustomerById(subscription.CustomerId);
//ensure that customer is registered (simple and fast way)
if (customer != null && CommonHelper.IsValidEmail(customer.Email))
{
var customerLanguageId = customer.GetAttributeFromEntity<string>(SystemCustomerAttributeNames.LanguageId, subscription.StoreId);
await _workflowMessageService.SendBackInStockNotification(customer, request.Product, subscription, customerLanguageId);
result++;
}
}
return subscriptions;
}
}
My test method:
[TestClass()]
public class SendNotificationsToSubscribersCommandHandlerTest
{
private Mock<ICustomerService> _mockCustomerService;
private Mock<IRepository<BackInStockSubscription>> _mockBackInStockSubscriptionRepository;
private Mock<IMongoQueryable<BackInStockSubscription>> _mongoQueryableMock;
private IQueryable<BackInStockSubscription> _expectedQueryable;
private List<BackInStockSubscription> _expected;
private Mock<IWorkflowMessageService> _mockWorkflowMessageService;
private SendNotificationsToSubscribersCommandHandler _handler;
private SendNotificationsToSubscribersCommand _sendNotificationsToSubscribersCommand;
[TestInitialize()]
public void Init()
{
_expected = new List<BackInStockSubscription>
{
new BackInStockSubscription { WarehouseId = "11", ProductId = "11" },
new BackInStockSubscription { WarehouseId = "11", ProductId = "11" }
};
_mockCustomerService = new Mock<ICustomerService>();
_mockBackInStockSubscriptionRepository = new Mock<IRepository<BackInStockSubscription>>();
_expectedQueryable = _expected.AsQueryable();
_mongoQueryableMock = new Mock<IMongoQueryable<BackInStockSubscription>>();
_mongoQueryableMock.As<IEnumerable<BackInStockSubscription>>();
_mongoQueryableMock.Setup(x => x.ElementType).Returns(_expectedQueryable.ElementType);
_mongoQueryableMock.Setup(x => x.Expression).Returns(_expectedQueryable.Expression);
_mongoQueryableMock.Setup(x => x.Provider).Returns(_expectedQueryable.Provider);
_mongoQueryableMock.Setup(x => x.GetEnumerator()).Returns(_expectedQueryable.GetEnumerator());
_mockBackInStockSubscriptionRepository.Setup(x => x.Table).Returns(_mongoQueryableMock.Object);
_mockWorkflowMessageService = new Mock<IWorkflowMessageService>();
_sendNotificationsToSubscribersCommand = new SendNotificationsToSubscribersCommand { Product = new Product { Id = "11"}, Warehouse = "11" };
_handler = new SendNotificationsToSubscribersCommandHandler(_mockCustomerService.Object, _mockWorkflowMessageService.Object, _mockBackInStockSubscriptionRepository.Object);
}
[TestMethod()]
public async Task GetAllSubscriptionsWithCorrectParamsProductId()
{
var result = await _handler.Handle(_sendNotificationsToSubscribersCommand, default);
var resultList = result.ToList();
Assert.AreEqual(resultList, _expected);
}
}
I get error on line
query = query.Where(biss => biss.ProductId == productId);
UPDATE
When I debug application, property _backInStockSubscriptionRepository.Table has Expression.Value = {aggregate([])}
If I debug test method property Table of Mock object has Expression.Value with Value = System.Collections.Generic.List<Grand.Domain.Catalog.BackInStockSubscription> with my two objects.
Any help is greatly appreciated
Take a look at here: How to mock a class that implements multiple interfaces
Try something like this:
_mongoQueryableMock = new Mock<IMongoQueryable<BackInStockSubscription>>();
_mongoQueryableMock.As<IEnumerable<BackInStockSubscription>>();
...

Unexpected null reference when testing with NUnit and Moq

I have been getting a null reference error when running my test but cant figure it out. Below is my test
[Test]
[TestCase(...)]
public void Get_ShouldReturnTradesMock(string field, Operator op, int dayManip, SortDirection sortDir, string filterTerm, int pageIndex, int pageSize, int expectedRecordMinSize)
{
using (var _imprintDbContext = new ImprintDbContext(_dbContextOptions))
{
var mockExecRepo = new Mock<IExecutionReportRepository>();
mockExecRepo.Setup(mock => mock.GetFilteredTrades(It.IsAny<IEnumerable<Query>>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>())).Verifiable();//.Returns<Task<PagedResult<ExecutionReport>>>(x => null);
var uow = new Mock<IUnitOfWork>();
uow.SetupGet(x => x.ExecutionReports).Returns(mockExecRepo.Object);
var controller = new TradesController(uow.Object);
var query = new Query()
{
Field = field,
Operator = op,
Search = DateTime.Now.Add(TimeSpan.FromDays(dayManip)).Date.ToString("yyyy-MM-dd"),
SortDirection = sortDir
};
TradesController.TradesBody tb = new TradesController.TradesBody()
{
queries = new[] { query },
filterTerm = filterTerm
};
var results = controller.Get(tb, pageIndex, pageSize);
uow.Verify(mock => mock.ExecutionReports.GetFilteredTrades(new[] { query }, pageIndex, pageSize, filterTerm), Times.Once());
}
}
And the definitions of some of the objects I am mocking:
public interface IExecutionReportRepository : IRepository<ExecutionReport>
{
...
Task<IPagedResult<ExecutionReport>> GetFilteredTrades(IEnumerable<Query> queries, int pageIndex, int pageSize, string filterTerm);
}
UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
private readonly DbContext _context;
public UnitOfWork(DbContext context, IExecutionReportRepository executionReportRepository)
{
_context = context;
ExecutionReports = executionReportRepository;
}
public IExecutionReportRepository ExecutionReports { get; }
}
TradesController:
public class TradesController : Controller
{
public class TradesBody
{
public IEnumerable<Query> queries;
public string filterTerm;
}
private readonly IUnitOfWork unitOfWork;
public TradesController(IUnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
}
/// <summary>
/// Gets a list of trades for the current date
/// </summary>
[HttpPost]
public async Task<IActionResult> Get([FromBody] TradesBody postBody, int pageIndex = 0, int pageSize = 100)
{
string filterTerm = postBody.filterTerm ?? "";
IEnumerable<Query> queries = postBody.queries;
IPagedResult<Domain.Entities.Core.ExecutionReport> queryResult;
queryResult = await unitOfWork.ExecutionReports.GetFilteredTrades(queries, pageIndex, pageSize, filterTerm); //Null reference error here
return Ok(queryResult);
}
}
When stepping through the code, I do not see any null objects and thus cannot actually see/understand where the null reference is actually being found, however I have noticed that I cannot see the method definition during debug time for 'GetFilteredTrades. Judging by this, my mocked method is not connecting to the method being executed, however I only have one GetFilteredTrades.
How do I resolve the null reference error being thrown in the TradesController and successfully run my test?
You are not setting up GetFilteredTrades to return anything so it is failing when you try to await it.
mockExecRepo
.Setup(mock => mock.GetFilteredTrades(It.IsAny<IEnumerable<Query>>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>()))
.ReturnAsync(Mock.Of<IPagedResult<ExecutionReport>>()) //<--THIS
.Verifiable();
Also the method under test is async, so the test should be async as well.
[Test]
[TestCase(...)]
public async Task Get_ShouldReturnTradesMock(string field, Operator op, int dayManip, SortDirection sortDir, string filterTerm, int pageIndex, int pageSize, int expectedRecordMinSize)
{
and the method under test call awaited
var results = await controller.Get(tb, pageIndex, pageSize);
Finally, you are verifying the wrong mock based on the setup. Since the mockExecRepo setup has Verifiable() then you can simply call Verify() on the mock.
//...
//Act
var results = await controller.Get(tb, pageIndex, pageSize);
//Assert
mockExecRepo.Verify();
to verify that it was invoked as expected.

Xunit test not working for mongodb service

I want to make a small XUnit test but it is not working. (AddTest is working but GetAllRestaurantsCountShouldReturnThree not working. )
I am new to unit testing and I don't know about Moq and how to use it.
How can I mock my IMongoService and get restaurant count?
MongoService.cs
public class MongoService : IMongoService
{
private readonly IMongoDatabase _mongoDatabase;
private readonly IMongoClient _mongoClient;
public MongoService()
{
_mongoClient = new MongoClient("mongodb://localhost:27017");
_mongoDatabase = _mongoClient.GetDatabase("Restaurant");
}
public List<RestaurantDto> GetAllRestaurants()
{
var collection = _mongoDatabase.GetCollection<RestaurantDto>("Restaurant");
return collection.Find(_ => true).ToList();
}
}
MongoServiceTest.cs
public class ReviewServiceTests
{
private List<RestaurantDto> _allRestaurants = new List<RestaurantDto>()
{
new RestaurantDto() {Name="xxx", ZipCode = "111" },
new RestaurantDto() {Name="yyy", ZipCode = "222" },
new RestaurantDto() {Name="zzz", ZipCode = "333" },
};
[Fact] //Not Working
public void GetAllRestaurantsCountShouldReturnThree()
{
var _mongoService = new Mock<IMongoService>();
_mongoService.Setup(x => x.GetAll()).Returns(_allRestaurants );
var count = _mongoService.GetAll(); //GetAll() not seeing
Assert.Equal(count, 3);
}
[Fact] //Working
public void AddTest()
{
Assert.Equal(10, Add(8, 2));
}
int Add(int a, int b)
{
return a + b;
}
}
You are using Moq incorrectly
[Fact]
public void GetAllRestaurantsCountShouldReturnThree() {
var mock = new Mock<IMongoService>();
mock.Setup(x => x.GetAllRestaurants()).Returns(_allRestaurants);
IMongoService mongoService = mock.Object;
var items = mongoService.GetAllRestaurants(); //Should call mocked service;
var count = items.Count;
Assert.Equal(count, 3);
}
Read up on the how to use Moq in their Quickstart

Entity framework error as"New transaction is not allowed because there are other threads running in the session

We are using entity framework codefirst approach
I am new to entity framework and I am facing error while trying to do "New transaction is not allowed because there are other threads running in the session.
public class DatabaseBackup : IDataBackup
{
private readonly IMonarchDbContext m_db;
public DatabaseBackup(IMonarchDbContext podb)
{
if (podb == null)
throw new ArgumentNullException("podb");
m_db = podb;
}
public DBBackupHistory GetLatestBackupHistory(DBBackupFrequency backupFrequency = DBBackupFrequency.Periodic)
{
DBBackupHistory result = null;
// get the backup history of the given backuptype and populate the objects
var configId = m_db.DBBackupConfigurations.Where(c => c.ScheduleType == (int)backupFrequency && c.BackupStatus == 1).Distinct().Select(c => c.ConfigurationId).DefaultIfEmpty(-1).First();
if (configId > 0)
{
result = m_db.DBBackupHistorys.Where(b => b.Status == 1 && b.ConfigurationId == configId).OrderByDescending(lb => lb.BackupDatetime).FirstOrDefault();
}
return result;
}
public IEnumerable<DBBackupConfiguration> GetAllConfiguration()
{
var result = m_db.DBBackupConfigurations.Where(c => c.BackupStatus == 1).OrderByDescending(c => c.ConfigurationId);
return result;
}
public void Backup(DBBackupConfiguration config, int fileIndex)
{
Console.WriteLine("Running DB Backup type {0} to device {1}", (DBBackupType)config.BackupType, fileIndex);
m_db.StoredProc.SPBackup(config, fileIndex);
}
I am calling the below methods in another class as follows
private readonly IDataBackup m_dataBackup;
public int PerformBackup(int defaultPollIntervalInMinutes = 15)
{
// polling interval in Minutes
int pollInterval = defaultPollIntervalInMinutes;
int fileIndex = getCurrentDumpFileIndex();
// check for the backup configuration
var configurations = m_dataBackup.GetAllConfiguration();
foreach (var config in configurations)
{
var lastBackup = m_dataBackup.GetLatestBackupHistory(DBBackupFrequency.Weekly);
if (lastBackup == null)
{
m_dataBackup.Backup(config, fileIndex + 1);
break;
}
Here is the Db Context class is as below
public class MonarchDbContext:DbContext,IMonarchDbContext
{
private IStoredProcedure m_storedProc;
private static object m_dbIntializerSet;
public MonarchDbContext(string nameOrConnectionString)
: base( nameOrConnectionString )
{
//-- Set the DB initializer only once.
System.Threading.LazyInitializer.EnsureInitialized( ref m_dbIntializerSet,()=>{
Database.SetInitializer<MonarchDbContext>(null);
//-- Give debug builds a chance to overwrite the above.
_SetInitializerForDebugBuilds();
return new object();
});
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
var csb = new SqlConnectionStringBuilder( this.Database.Connection.ConnectionString );
csb.MultipleActiveResultSets = true;
this.Database.Connection.ConnectionString = csb.ToString();
var objectContext = ( this as IObjectContextAdapter ).ObjectContext;
objectContext.CommandTimeout = 3600;
}
#region Public "Tables"
public IDbSet<DBBackupConfiguration> DBBackupConfigurations { get; set; }
public IDbSet<DBBackupHistory> DBBackupHistorys { get; set; }
public IStoredProcedure StoredProc
{
get
{
return System.Threading.LazyInitializer.EnsureInitialized(ref m_storedProc, () => new BackupStoredProc(this.Database));
}
}
#endregion
please let me know how can i solve the issue.
I found the issue
I need to add toList() at the end of the Linq code and it just worked for me.
public IEnumerable<DBBackupConfiguration> GetAllConfiguration()
{
var result = m_db.DBBackupConfigurations.Where(c => c.BackupStatus == 1).OrderByDescending(c => c.ConfigurationId).ToList();
return result;
}
Just add the List to Ienumerbale types

Categories