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
Related
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.
In short, I have two NUnit test cases in a Standard project using Moq that when I run them individually, they pass, but run separately the second one fails. Specifically, the first takes 1.9s to run, and the second fails immediately (118ms) saying the result is 0 though it should be 1.
Code (included sample setup code for orders, test code and code being tested):
[SetUp]
public void Initialize()
{
clocationData = new CalfeeLocationData();
clocationData.ApplyDefaultMockDataset();
mlocationData = new MeetingLocationData();
mlocationData.ApplyDefaultMockDataset();
mlocationLayoutData = new MeetingLocationLayoutData();
mlocationLayoutData.ApplyDefaultMockDataset();
orderData = new OrderData();
orderData.ApplyDefaultMockDataset();
orderDetailData = new OrderDetailData();
orderDetailData.ApplyDefaultMockDataset();
orderRepository = (OrderRepository)orderData.GetRepository();
}
public override void ApplyDefaultMockDataset()
{
ClearMockData();
SetDefaultOrder();
}
private void SetDefaultOrder()
{
var ord = new Order()
{
EntryId = "000-333",
GlobalId = "000-999-99999",
OrganizerGraphId = "Id",
BillingInfo = "Nada",
OtherInstructions = "No Other Complications",
MeetingLocationId = 79
};
AddMockData(ord);
}
[TestCase(true, 1)]
[TestCase(false, 1)]
public void GetAllByCreator_OneTest(bool includeDelete, int expectedCount)
{
var saveModel = CreateOrder();
orderRepository.Save(saveModel);
var foundOrder = orderRepository.GetById(saveModel.OrderId);
foundOrder.OrganizerEmail = testEmail;
orderRepository.Save(foundOrder);
var foundOrders = orderRepository.GetAllByOrganizer(saveModel.OrganizerEmail, includeDelete);
Assert.AreEqual(expectedCount, foundOrders.Count);
}
public List<Order> GetAllByOrganizer(string organizerEmail, bool getDeleted = false)
{
var baseQuery = GetDataQueryBase();
var orders = baseQuery.Where(mod => mod.OrganizerEmail == organizerEmail);
if (!getDeleted) orders = orders.Where(mod => !mod.Deleted);
return orders.OrderBy(c => c.CreatedDate).ToList();
}
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 **
I'm new to unit testing, and trying to mock postContinent. But gives null and BadRequestObjectResult.
ContinentControllerTests
public class ContinentControllerTests {
// RepoMocks
private readonly Mock<IContinentRepository> _continentRepoMock = new Mock<IContinentRepository>();
private readonly Mock<ICountryRepository> _countryRepoMock = new Mock<ICountryRepository>();
private readonly Mock<ICityRepository> _cityRepoMock = new Mock<ICityRepository>();
// Controller
private readonly ContinentController _continentController;
public ContinentControllerTests() {
_continentServiceMock = new ContinentService(_continentRepoMock.Object);
_continentController = new ContinentController(new ContinentService(_continentRepoMock.Object), new CountryService(_countryRepoMock.Object), new CityService(_cityRepoMock.Object));
}
[Fact]
public void PostContinent_ValidInput_ReturnsCreateAtAction() {
// Arrange
_continentRepoMock
.Setup(repo => repo.HeeftContinent("Test"))
.Returns(false);
_continentRepoMock
.Setup(repo => repo.BestaatContinent(new Continent("Test", new List<Country>())))
.Returns(false);
_continentRepoMock
.Setup(repo => repo.VoegContinentToe(new Continent("Test", new List<Country>())))
.Returns(new Continent(1, "Test", new List<Country>()));
// Act
var response = _continentController.PostContinent(new ContinentInputDTO { Name = "Test" });
// Assert
Assert.IsType<CreatedAtActionResult>(response.Result);
}
}
ContinentController
public class ContinentController : ControllerBase {
private string _hostURL = $"http://localhost:5000/api/continent";
private string _riverURL = $"http://localhost:5000/api/river";
private ContinentService _continentService;
private CountryService _countryService;
private CityService _cityService;
public ContinentController(ContinentService continentService, CountryService countryService, CityService cityService) {
_continentService = continentService;
_countryService = countryService;
_cityService = cityService;
}
[HttpPost]
public ActionResult<ContinentOutputDTO> PostContinent([FromBody] ContinentInputDTO continentDto) {
try {
if (_continentService.HeeftContinent(continentDto.Name)) { return BadRequest("Continent naam moet unique zijn!"); }
var mappedContinent = MapToDomain.MapToContinentDomain(continentDto);
Continent continent = _continentService.VoegContinentToe(mappedContinent);
return CreatedAtAction(nameof(GetContinent), new { continentId = continent.Id },
MapFromDomain.MapFromContinentDomain(_hostURL, continent));
}
catch (Exception ex) { return BadRequest(ex.Message); }
}
}
ContinentService
public class ContinentService {
private readonly IContinentRepository _repo;
public ContinentService(IContinentRepository repo) { _repo = repo;}
public Continent VoegContinentToe(Continent c) {
if (c == null) throw new ContinentServiceException("VoegContinentToe : continent is null");
if (_repo.BestaatContinent(c)) throw new ContinentServiceException("VoegContinentToe : continent bestaat reeds");
try {return _repo.VoegContinentToe(c);}
catch (Exception ex) { throw new ContinentServiceException("VoegContinentToe: ", ex);}
}
}
Error:
Message: 
Assert.IsType() Failure
Expected: Microsoft.AspNetCore.Mvc.CreatedAtActionResult
Actual: Microsoft.AspNetCore.Mvc.BadRequestObjectResult
The problem is in your Setup function. Reference types are equal only if you have overridden the equals function or if the are the exact same reference.
So by setting it up with the new keyword, it will never match the execution time object.
Try the It.IsAny<T> function from MOQ to verify.
Check the example here: https://documentation.help/Moq/3CF54A74.htm
// Throws an exception for a call to Remove with any string value.
mock.Setup(x => x.Remove(It.IsAny<string>())).Throws(new InvalidOperationException());
Example. Apply to all setups.
_continentRepoMock
.Setup(repo => repo.BestaatContinent(It.IsAny<Continent>()))
.Returns(false);
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>>();
...