I am trying to understand a behavior that is occurring in my application. I have mocked out my DbContext and when I make a call get items from the dbContext.Set<T>().ToList(), the second call does not contain my mocked data. I am not sure why this happens since that data should still exist. Please see code below:
SUT:
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public decimal Salary { get; set; }
}
public class EmployeeDb
: DbContext
{
public EmployeeDb()
{
}
public virtual IDbSet<Employee> Employees { get; set; }
}
UNIT TEST:
public class MockDatabase
{
public Mock<EmployeeDb> SetMockData()
{
var mockDb = new Mock<EmployeeDb>();
mockDb.Setup(i => i.Set<Employee>()).Returns(GetMockSet(Employees).Object);
mockDb.SetupGet(i => i.Employees).Returns(() => GetMockSet(Employees).Object);
return mockDb;
}
private List<Employee> _providers;
private List<Employee> Employees => _providers ?? (_providers = new List<Employee>
{
GetEmployee(1),
GetEmployee(2),
GetEmployee(3),
GetEmployee(4),
GetEmployee(5),
});
private static Employee GetEmployee(int id)
{
return new Employee
{
FirstName = Faker.Name.First(),
LastName = Faker.Name.Last(),
Age = Faker.RandomNumber.Next(50),
Id = id,
Salary = Faker.RandomNumber.Next(100000)
};
}
#region Hood
public static Mock<DbSet<T>> GetMockSet<T>(IList<T> items) where T : class
{
var querable = items.AsQueryable();
var mockSet = new Mock<DbSet<T>>();
mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(querable.Provider);
mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(querable.Expression);
mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(querable.ElementType);
mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(querable.GetEnumerator());
mockSet.Setup(i => i.Add(It.IsAny<T>())).Callback(delegate (T item) {
items.Add(item);
});
return mockSet;
}
#endregion
}
[TestClass]
public class UnitTest1
{
private EmployeeDb _context;
[TestInitialize]
public void TestInitialize()
{
var mockDb = new MockDatabase();
_context = mockDb.SetMockData().Object;
}
[TestMethod]
public void Test_CallTwice_ReturnsEqualCount()
{
var emps = _context.Set<Employee>().ToList();
var emps2 = _context.Set<Employee>().ToList();
Assert.IsTrue(emps.Count == emps2.Count);
// -- This works
//var empCount = _context.Set<Employee>().Count();
//var empCount2 = _context.Set<Employee>().Count();
//Assert.IsTrue(empCount == empCount2);
}
}
Is there something I am not getting about this code? Is there something Moq does with the ToList()?
ToList enumerates the set when invoked, but the enumerator is forward only, so after the first call it is already at the end.
When setting up the GetEnumerator use the function overload of the Returns in order to allow multiple calls other wise the same enumerator will be returned every time and you get the behavior you experienced.
mockSet.As<IQueryable<T>>()
.Setup(m => m.GetEnumerator())
.Returns(() => querable.GetEnumerator()); //<-- function
Related
I'm having problem when i create a index.
This is my code:
private static IMongoCollection<IPageItem> GetCollection()
{
return Connection.Database.GetCollection<IPageItem>("SystemPages");
}
internal static IEnumerable<Task> CreateIndex()
{
BsonClassMap.RegisterClassMap<NewsItem>();
var work = new List<Task>();
var coll = GetCollection();
var builder= Builders<IPageItem>.IndexKeys;
var btIndexes = new List<CreateIndexModel<IPageItem>>
{
new(builder.Ascending(x => x.PageId), new CreateIndexOptions { Unique = true })
};
work.Add(coll.Indexes.CreateManyAsync(btIndexes));
return work;
}
public interface IPageItem
{
public Guid PageId { get; set; }
}
public class NewsItem : IPageItem
{
public Guid PageId { get; set; }
public string Summery { get; set; }
}
When i call, CreateIndex() i receive, Unable to determine the serialization information for x => Convert(x.PageId, Object).)
Can I not use one interface when create/get a collection?
Given the following Automapper profile :
public class MyProfile: Profile
{
private int? _injectedInt;
public MyProfile()
{
CreateMap<objectA, objectB>()
.ForMember(e => e.myNullableInt, x => x.MapFrom(s =>_injectedInt.HasValue ? 100 : 0));
}
}
And the following code :
var result = queryableOfObjectA.ProjectTo<objectB>(new { _injectedInt = 1 });
var resultingValue = result.FirstOrDefault().myNullableInt;
Why is "resultingValue" returning 0 instead of 100?
I can't see what I have done wrong from the docs:
http://docs.automapper.org/en/stable/Queryable-Extensions.html#parameterization
I think the place where _injectedInt is declared might be the issue. I have written following test and 100 is returned.
[TestClass]
public class UnitTest19
{
[TestMethod]
public void TestMethod1()
{
Mapper.Initialize(expression => expression.AddProfile(new MyProfile()));
var queryableOfObjectA = new List<objectA>
{
new objectA
{
myNullableInt = 10
}
};
var result = queryableOfObjectA.AsQueryable().ProjectTo<objectB>(new { _injectedInt = (int?)1 });
var resultingValue = result.FirstOrDefault()?.myNullableInt;
Assert.AreEqual(100, resultingValue);
}
}
public class MyProfile : Profile
{
public MyProfile()
{
int? _injectedInt = null;
CreateMap<objectA, objectB>()
.ForMember(e => e.myNullableInt, x => x.MapFrom(s => _injectedInt.HasValue ? 100 : 0));
}
}
public class objectA
{
public int myNullableInt { get; set; }
}
public class objectB
{
public int myNullableInt { get; set; }
}
Hey I'm trying to map my generic class to concrete class but using it's interface.
My service returns me data which type is
IPaggedResults<Customer>
and I want to be able to map this to
IPaggedResults<CustomerDto>
It works if I invoke mapping with:
_mapper.Map<PaggedResults<CustomerDto>>
but I want use following syntax:
_mapper.Map<IPaggedResults<CustomerDto>>
public class PaggedResults<T> : IPaggedResults<T>
{
public IEnumerable<T> Results { get; protected set; }
public int TotalResults { get; protected set; }
public int TotalPages { get; protected set; }
public int ResultsPerPage { get; protected set; }
public PaggedResults(IEnumerable<T> results, int totalResults, int resultsPerPage)
{
Results = results;
TotalResults = totalResults;
TotalPages = totalResults / resultsPerPage;
ResultsPerPage = resultsPerPage;
}
}
public class CustomerDto
{
public int Id { get; set; }
public string Name { get; set; }
public string NIP { get; set; }
}
My mapper configuration:
public static IMapper Initialize()
=> new MapperConfiguration(cfg =>
{
cfg.CreateMap<CustomerCompany, CustomerDto>();
cfg.CreateMap(typeof(IPaggedResults<>), typeof(PaggedResults<>));
cfg.CreateMap(typeof(IPaggedResults<>), typeof(IPaggedResults<>)).As(typeof(PaggedResults<>));
}).CreateMapper();
Im'using Automapper by Jimmy Bogard.
I could achieve it through the following code:
Create an extension for IMapperConfigurationExpression
public static class IMapperConfigurationExpressionExtensions
{
public static void MapPaggedResults<TSource, TDestination>(this IMapperConfigurationExpression exp){
exp.CreateMap(typeof(PaggedResults<TSource>), typeof(IPaggedResults<TDestination>))
.ConstructUsing((source, ctx) => { return ctx.Mapper.Map<PaggedResults<TDestination>>(source) as IPaggedResults<TDestination>; });
}
}
Then use this configuration:
public static IMapper Initialize()
=> new MapperConfiguration(cfg =>
{
cfg.CreateMap(typeof(IPaggedResults<>), typeof(PaggedResults<>));
cfg.MapPaggedResults<CustomerCompany, CustomerDto>();
}).CreateMapper();
Then both results can be obtained:
var _mapper = Initialize();
IPaggedResults<CustomerCompany> source = new PaggedResults<CustomerCompany>(
new List<CustomerCompany>() { new CustomerCompany() {Id =42, Name = "SomeName", NIP = "someNIP" } }, 1, 1);
var resut = _mapper.Map<PaggedResults<CustomerDto>>(source);
var resut2 = _mapper.Map<IPaggedResults<CustomerDto>>(source);
I want to saw that I do not care what is in the Find clause. Just give me null.
Here is the test
[Fact]
public void VerifyIndexViewType()
{
// Arrange
var mockUserProvider = new Mock<IUserProvider>();
mockUserProvider.Setup(x => x.GetUserId()).Returns("any-value-here");
var mockUnitOfWork = new Mock<IUnitOfWork>();
//how would I just return an object or null for example.. this doesnt work
// mockUnitOfWork.Setup(x => x.UserProfileDataRepository.Find(u => u.ApplicationUserId == "any value here")).Returns((IRepository<UserProfileData>)null);
var controller = new ProfileController(mockUnitOfWork.Object, mockUserProvider.Object);
// Act
var result = controller.Update();
// Assert
Assert.IsType<ViewResult>(result);
}
For the following controller and action
public class ProfileController : BaseController
{
private IUnitOfWork _unitOfWork;
private readonly IUserProvider _requestUserProvider;
public ProfileController(IUnitOfWork unitOfWork,
IUserProvider requestUserProvider)
: base(unitOfWork, requestUserProvider)
{
_unitOfWork = unitOfWork;
_requestUserProvider = requestUserProvider;
}
public IActionResult Update()
{
//this is easy
string userId = _requestUserProvider.GetUserId();
//how do I do the setup in moq for this?
IEnumerable<UserProfileData> userProfileQuestions = _unitOfWork.UserProfileDataRepository.Find(x => x.ApplicationUserId == userId);
if (userProfileQuestions != null)
{
ProfileViewModel profileViewModel = new ProfileViewModel();
profileViewModel.UserProfileData = userProfileQuestions.FirstOrDefault();
return View(profileViewModel);
}
return View("Error", "Home");
}
EDIT 1: MY IUnitOfWork and implementation of the method
public interface IUnitOfWork
{
IRepository<ApplicationUser> ApplicationUserRepository { get; }
IRepository<RefMedicalSpecialty> RefMedicalSpecialtyRepository { get; }
IRepository<RefProgramDetailData> RefProgramDetailDataRepository { get; }
IRepository<RefProgramProfileData> ProgramProfileDataRepository { get; }
IRepository<UserProgram> UserProgramRepository { get; }
IRepository<UserFeedback> UserFeedbackRepository { get; }
IRepository<UserAction> UserActionRepository { get; }
IRepository<UserProfileData> UserProfileDataRepository { get; }
IRepository<RawCredential> RawCredentialRepository { get; }
IRepository<RefProgramCharacteristic> RefProgramCharacteristicRepository { get; }
IRepository<UserProgramRefProgramCharacteristic> UserProgramRefProgramCharacteristicRepository { get; }
void Commit();
void RejectChanges();
void Dispose();
}
public IRepository<UserProfileData> UserProfileDataRepository =>
new Repository<UserProfileData>(_retContext);
Declare the Method Find as virtual
public virtual YourType Find(Expression<Func<YourClass, bool>> yourfunc)
and the mock as:
mockUnitOfWork.Setup(x => x.UserProfileDataRepository.Find(It.IsAny<Expression<Func<YourClass, bool>>>()).Returns(DefineYourReturn);
My test is setup with mocking data like this
var persons = new List<Core.Domain.Person>
{
new Core.Domain.Person { DisplayName = "Coordinator 1", Email="coordinator01#wur.nl", WurAccount = "coord001" },
new Core.Domain.Person { DisplayName = "Coordinator 2", Email="coordinator02#wur.nl", WurAccount = "coord002" }
};
this.mockUnitOfWork.Setup(x => x.Query<Core.Domain.Person>()).Returns(persons.AsQueryable);
In the code to test the persons are retrieved like this
private Dictionary<string, Domain.Person> GetPersons(IEnumerable<string> wurAccounts)
{
var accounts = wurAccounts.ToList();
return this.session.Query<Domain.Person>()
.Where(x => accounts.Contains(x.WurAccount))
.ToDictionary(x => x.WurAccount);
}
When I run the test I get a NullReferenceException here:
at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery)
at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
at Remotion.Linq.QueryableBase`1.GetEnumerator()
at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
at System.Linq.Enumerable.ToDictionary[TSource,TKey](IEnumerable`1 source, Func`2 keySelector)
at Wur.P2G.Core.Services.PersonSynchronizer.GetPersons(IEnumerable`1 wurAccounts) in C:\Projects\P2G\P2G\Sources\Wur.P2G.Core\Services\PersonSynchronizer.cs:line 112
EDIT
I was able to boile it down to this piece of code that still causes the NullReference Exception:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using NHibernate;
using NHibernate.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Wur.P2G.Core.Services.Tests
{
public interface IUnitOfWork : IDisposable
{
ISession Session { get; }
IQueryable<T> Query<T>();
void BeginTransaction();
void Commit();
void Rollback();
}
public class Person
{
public virtual string WurAccount { get; set; }
public virtual string DisplayName { get; set; }
public virtual string Email { get; set; }
public virtual bool HasValidEmail => true;
public override string ToString() => WurAccount;
}
[TestClass()]
public class PersonSynchronizerTests
{
private Mock<IUnitOfWork> mockUnitOfWork;
private Mock<ISession> mockSession;
[TestInitialize]
public void Initialize()
{
this.mockUnitOfWork = new Mock<IUnitOfWork>();
this.mockSession = new Mock<ISession>();
this.mockUnitOfWork.Setup(x => x.Session).Returns(this.mockSession.Object);
}
[TestMethod()]
public void GetPersonsTest()
{
var persons = new List<Person>
{
new Person { DisplayName = "Coordinator 1", Email="coordinator01#wur.nl", WurAccount = "coord001" },
new Person { DisplayName = "Coordinator 2", Email="coordinator02#wur.nl", WurAccount = "coord002" }
};
this.mockUnitOfWork.Setup(x => x.Query<Person>()).Returns(persons.AsQueryable);
var wurAccounts = new[] { "coord001", "coord002" };
var accounts = wurAccounts.ToList();
var personsRead = mockSession.Object.Query<Person>()
.Where(x => accounts.Contains(x.WurAccount))
.ToDictionary(x => x.WurAccount);
}
}
}
Some more text because the stupid editor want it from me.
While the error message shows that the problem is related to NHibernate.Linq, None of the code shown so far is related to NHibernate unless there is something you are not showing that is using it.
The code shown so far should work as expected as demonstrated by the following minimal, complete and verifiable example based on the original example provided.
[TestClass]
public class PersonSynchronizerTest {
[TestMethod]
public void PersonSynchronizer_GetPerson_Should_Return_Two() {
//Arrange
var wurAccounts = new[] { "coord001", "coord002" };
var persons = new List<Person> {
new Person { DisplayName = "Coordinator 1", Email="coordinator01#wur.nl", WurAccount = wurAccounts[0] },
new Person { DisplayName = "Coordinator 2", Email="coordinator02#wur.nl", WurAccount = wurAccounts[1] }
};
var mockSession = new Mock<ISession>();
mockSession.Setup(_ => _.Query<Person>()).Returns(persons.AsQueryable); //<-- setup session
var mockUnitOfWork = new Mock<IUnitOfWork>();
mockUnitOfWork.Setup(_ => _.Query<Person>()).Returns(persons.AsQueryable);
mockUnitOfWork.Setup(_ => _.Session).Returns(mockSession.Object); //<-- UoW returns session
var subject = new PersonSynchronizer(mockUnitOfWork.Object);
//Act
var actual = subject.GetPersons(wurAccounts);
//Assert
actual.Should()
.NotBeNull()
.And.HaveCount(wurAccounts.Length);
}
public class PersonSynchronizer {
private IUnitOfWork unitOfWork;
private ISession session;
public PersonSynchronizer(IUnitOfWork uow) {
this.unitOfWork = uow;
this.session = unitOfWork.Session;
}
public Dictionary<string, Person> GetPersons(IEnumerable<string> wurAccounts) {
var accounts = wurAccounts.ToList();
return this.session.Query<Person>()
.Where(x => accounts.Contains(x.WurAccount))
.ToDictionary(x => x.WurAccount);
}
}
public class Person {
public string DisplayName { get; set; }
public string Email { get; set; }
public string WurAccount { get; set; }
}
public interface IUnitOfWork : IDisposable {
ISession Session { get; }
IQueryable<T> Query<T>();
void BeginTransaction();
void Commit();
void Rollback();
}
public interface ISession {
IQueryable<T> Query<T>();
}
}
The snippet above passes as expected when tested.
I suggest reviewing if there are any NHibernate extension methods being called that may be conflicting with the default Linq Extensions, causing the issues encountered.