I got a problem with Moq and Automapper regarding IDataReader.
I found an example on stackoverflow and modified the code.
public static IDataReader MockIDataReader<T>(List<T> ojectsToEmulate) where T : class
{
var moq = new Mock<IDataReader>();
// This var stores current position in 'ojectsToEmulate' list
var count = 0;
moq.Setup(x => x.Read())
// Return 'True' while list still has an item
.Returns(() => count < ojectsToEmulate.Count)
// Go to next position
.Callback(() => count++);
var properties = typeof (T).GetProperties();
foreach (PropertyInfo t in properties)
{
var propName = t.Name;
moq.Setup(x => x[propName]).Returns(() => ojectsToEmulate[count].GetType().GetProperty(propName).GetValue(ojectsToEmulate[count],null));
}
return moq.Object;
}
}
My mapping:
Mapper.Configuration.CreateMap(typeof(IDataReader), typeof(IEnumerable<T>));
var result = Mapper.Map<IDataReader, IEnumerable<T>>(reader);
The problem I got here is that my result has 1 result a cityModel but all it's properties are null. If I check the value from my mocked reader like reader["name"] I got the "Alingsås" value so the mocking is correct but Automapper seams to have the problem.
I use a List of objects that I pass to my method that mocks it all.
var cityModel = new CityModel();
cityModel.Name = "Alingsås";
cityModel.Id = "SE";
cityModel.CountryId = "SE";
var cityModels = new List<CityModel>();
cityModels.Add(cityModel);
_fakeReader = MockTester.MockIDataReader(cityModels);
The code works fine, no exception is thrown, but the mapper gives me an object without the
valules. I can see in the debugger my reflection code works but it seams like my
x["Name"] aren't the method Automapper call from IDataReader? Or is it?
What can be wrong here?
Automapper internally uses the int indexer of IDataReader so you need to call Setup on that instead of Item[String].
Checking the Automapper's source you need to setup some additional methods to make it work:
//...
var index = 0;
foreach (PropertyInfo t in properties)
{
var propName = t.Name;
int index1 = index; // avoid access to modified closure
moq.Setup(x => x.GetFieldType(index1)).Returns(t.PropertyType);
moq.Setup(x => x.GetName(index1)).Returns(propName);
moq.Setup(x => x[index1])
.Returns(ojectsToEmulate[count]
.GetType()
.GetProperty(propName).GetValue(ojectsToEmulate[count], null));
index++;
}
moq.Setup(x => x.FieldCount).Returns(properties.Length);
//...
Related
I am using Moq to mock Entity Framework Core's DbSet to return items in a test.
I got a test which gets the first item in the db set and checks its count. At the first time, I manage to get the object stored in the DbSet and the count is 1. At the second time, I get null in return but the count of the collection is still 1. When I debug and inspect, the collection inside the DbSet gives a message "Enumeration yielded no results"
[TestMethod]
public void MyTest()
{
var dbMock = GetDbContextMock();
Assert.AreEqual(1, dbMock.Object.Table2.Count()); //passes
Table2Model item1 = dbMock.Object.Table2.AsEnumerable().Where(x => x.DataCenter == "DataCenter").FirstOrDefault(); // item1 is an object
Assert.AreEqual(1, dbMock.Object.CurrentRunningServices.Count()); //passes
Table2Model item2 = dbMock.Object.Table2.AsEnumerable().Where(x => x.DataCenter == "DataCenter").FirstOrDefault(); //item2 is null
Assert.AreEqual(1, dbMock.Object.CurrentRunningServices.Count()); //passes
}
Why does the second time I get null instead of an object? It feels like some inner pointer somewhere didn't go back to the start of the collection of the DbSet.
Implementation:
private List<Table2Model> GetMockTable2List()
{
Table2Model item = new Table2Model();
item.DataCenter = "DataCenter";
return new List<Table2Model>() { item } ;
}
private Mock<MyDbContext> GetDbContextMock()
{
var realDal = new MyDbContext();
var dbContextMock = new Mock<MyDbContext>();
dbContextMock.SetupAllProperties();
dbContextMock.Object.Table1= realDal.Table1;
var table2List = GetMockTable2List().AsQueryable();
var table2DbSetMock = new Mock<DbSet<Table2Model>>();
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.Provider).Returns(table2List.Provider);
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.Expression).Returns(table2List.Expression);
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.ElementType).Returns(table2List.ElementType);
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.GetEnumerator()).Returns(table2List.GetEnumerator());
dbContextMock.Object.Table2 = table2DbSetMock.Object;
return dbContextMock;
}
The problem is with the line
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.GetEnumerator()).Returns(table2List.GetEnumerator());
It returns the same enumerator every time. The way to fix it is to change the Returns value to a lambda:
table2DbSetMock.As<IQueryable<Table2Model>>().Setup(m => m.GetEnumerator()).Returns(() => table2List.GetEnumerator());
How can I get a list of entity types that are part of the model, so I can test that the model actually works with that entity type?
var dcx = new MyDbContext();
var lst = new List<Type>();
//populate the list here somehow
//...
foreach (var t in lst) {
var set = dcx.Set(t); //I'm trying to avoid an exception here
try {
var test = set.FirstOrDefault();
} catch (Exception ex) {
Console.WriteLine("{0} has an error", t);
}
}
NB: It is perfectly possible to query dcx.Set(t) even if there is no corresponding DbSet property on MyDbContext; therefore it's not enough to iterate via reflection over the properties of MyDbContext whose return type's generic definition is DbSet<T> or even IDbSet<T>.
Maybe something like this?
var types = typeof(MyDbContext)
.GetProperties()
.Where(prop => prop.PropertyType.IsGenericType)
.Where(prop => prop.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
.Select(prop => prop.PropertyType.GenericTypeArguments.First())
.Distinct();
Thanks to the link in #GertArnold 's comment, I am now using the following:
var dcx = new MyDbContext();
var objContext = ((IObjectContextAdapter)dcx).ObjectContext;
var types = objContext.MetadataWorkspace.GetItems<EntityType>(DataSpace.OSpace).Select(x => Type.GetType(x.FullName));
foreach (var t in lst) {
...
I am using the Linq.Dynamic Library and EF6. I am attempting to select only the fields from a database that my user selects.
However, all that is returned is a List<object>, I have attempted to Cast<dynamic>, and every way I can think of, but no matter what the object has 0 fields.
I have also tried explicitly declaring as an IEnumerable and that too was unsuccessful, and was unable to call .ToList(), without first calling Cast<T> which too was unsuccessful.
When converting one of the objects to string I get: "{filenumber=345400, custom2=, custom3=, custom6=4076995332, custom8=4072121417}".
The data is being returned I simply cannot cast it to the appropriate type.
var query = cmax.dbases
.Where(w => statuses.Any(a => w.statusname == a) && portfolios.Any(a => w.portfolio == a))
.Select(string.Format("new ({0})", string.Join(",", fields)))
.Take(Math.Min((int) takeAmount, count - taken));
var take = await query.ToListAsync();
take.ForEach(data => {
var type = take.GetType();
var properties = type.GetProperties();
var propCount = properties.Count();
properties.ToList().ForEach(prop => {
var name = prop.Name;
});
});
In one of my use cases I have converted the results to List<string[]> through an extension for IQueryable. As I know my column order in Select("New (columnNames...) "), I could easily figure out which one is which.
so here is the code of the extension
public static IList<string[]> ToStringArray(this IQueryable queryFinal)
{
var query = (IQueryable<dynamic>)queryFinal;
IList<dynamic> data = query.ToList();
System.Reflection.PropertyInfo[] props = null;
if (data.Count > 0) props = data[0].GetType().GetProperties();
if (props == null) return new List<string[]>();
/*I do other things using reflection here*/
return data.Select(d => props.Select(p => (p.GetValue(d, null) ?? string.Empty).ToString()).OfType<string>().ToArray()).ToList();
}
use it as
var result = query.ToStringArray();
The only viable solution I found was to manually parse the data in the string:
take.ForEach(data =>
{
var dbtrData = new DebtorData();
var cleaned = data.ToString().Replace("{", "").Replace("}", "");
var pairs = cleaned.Split(',');
pairs.ToList().ForEach(pair =>
{
var key = pair.Split('=')[0].Replace(" ", "");
var value = pair.Split('=')[1];
//USEDATA
}
});
I'm trying to wrap the results of a query with a class called QueryResultViewModel from a list of dynamic objects retrieved by LINQ. These contain a integer field called Worked. I should not use a non-dynamic type because depending on the query it has other fields. I tried that:
var query = new HoursQuery( .. parameters .. );
this.Result = new ObservableCollection<QueryResultViewModel>(
query.Execute().Select( x => new QueryResultViewModel( x.Worked )));
But I got "'object' does not contain a definition for 'Worked'" and I don't know If it can be fixed without changing query's return type.
The Execute code may be useful too:
var res = some_list.GroupBy(a => new { a.Employee, a.RelatedTask, a.Start.Month })
.Select(g => new { K = g.Key, Worked = g.Sum(s => s.Duration.TotalHours) });
EDIT: This worked great but maybe it's not very elegant.
public class HQueryDTO
{
public double Worked;
public object K;
}
public IEnumerable<dynamic> Execute()
{
var list = base.Execute();
return res = list.GroupBy(a => new { a.Employee, a.RelatedTask } )
.Select(g => new HQueryDTO { K = g.Key, Worked = g.Sum(s => s.Duration.TotalHours) });
}
Now that the result has a type it can be returned dynamic.
I'm assuming you get that error at compile-time, in which case simply introduce dynamic via a cast:
.Select(x => new QueryResultViewModel( ((dynamic)x).Worked ))
I assume that the signature of Execute is something like object Execute(). If you return dynamic, it should work.
I have the following sample test code
public Stage Test(Stage Stage)
{
var StartStage = StageRepository.Single(x => x.Order == 1);
var EndStage = StageRepository.Single(x => x.Order == 5);
var ErrorStage = StageRepository.Single(x => x.Name == "Error");
if (Stage == StartStage)
{
return EndStage;
}
else
{
return ErrorStage;
}
}
And I am trying to test it using the following unit test
[TestMethod]
public void XXXTest()
{
//// Arrange
var AutoMocker = new RhinoAutoMocker<StageService>(MockMode.AAA);
MockRepository mockRepository = new MockRepository();
var MockStageRepository = AutoMocker.Get<IRepository<Stage>>();
Stage StartStage = mockRepository.Stub<Stage>();
StartStage.Order = 1;
Stage EndStage = mockRepository.Stub<Stage>();
EndStage.Order = 5;
Stage ErrorStage = mockRepository.Stub<Stage>();
ErrorStage.Name = "Error";
System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> StartParam = x => x.Order == 1;
MockStageRepository
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(StartParam)))
.Return(StartStage);
System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> EndParam = x => x.Order == 1;
MockStageRepository
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(EndParam)))
.Return(EndStage);
System.Linq.Expressions.Expression<Func<Entities.Stage, bool>> ErrorParam = x => x.Order == 1;
MockStageRepository
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Is.Equal(ErrorParam)))
.Return(ErrorStage);
StageService StageService = AutoMocker.ClassUnderTest;
//Act
var ReturnStage = StageService.Test(StartStage);
//Assert
Assert.AreEqual(ReturnStage, EndStage);
}
However this is not working as it is not returning anything when I call StageRepository.Single(). If I change the stub code to ignore the argument then it does return something but it will be the same object returned for each call to Single() which I don't want.
Is it possible to configure RhinoMocks in such a way as to return different objects from a stub depending on the lambda that is passed into it?
I think the root of your problem is that equality on the Expression<Func<T,U>> type is performed by reference rather than value. That means your telling Rhino Mocks to look for instances of expressions created in the test rather than the ones created in the code your testing.
Two possible approaches come to mind:
One would be to provide a way to pass the lambda expressions in to the Stage class from the test, so that when the argument checks happen they are working against the same instances.
Maybe something like:
internal void SetStartStage(Expression<Func<Entities.Stage,bool>> predicate)
{
...
}
The inverse of this would also work, i.e. provide the Expression objects as fields/properties that can be accessed by you're test, and then use those when setting up your mock:
internal Expression<Func<Entities.State,bool>> StartStagePredicate
{
get{ return x => x.Order == 1; }
}
Another option would be to use the Matches method on Args to see if the argument checks the Stage object state correctly. This would require creating some Stage objects in your test that would match the criteria:
var startStageTester = new Stage { Order = 1 };
MockStageRepository
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Matches(y => y.Compile()(startStageTester)))
.Return(StartStage);
The call to Compile() is a little jarring, but since you're dealing with an Expression and not a straight-up lambda, you've got to compile it in order to evaluate it.
Now, if a Stage is something that is hard to create, then you may need to create a Mock/Stub of one (or use you're StartStage) and have it return 1 from the Order property (in the case of the StartStage anyway).
There are probably some others I'm not thinking of at the moment as well.
IF the linq condition is not important, I would propose to match it as any, something like this
repository.Stub(x => x.Find(Arg<System.Linq.Expressions.Expression<Func<Entity, bool>>>.Is.Anything)).Return(entitiesList.AsQueryable());
Hope this help.
Thanks for that. That worked a treat. The one thing that I was missing was the Compile method on an ExpressionTree. There is a small bug in your sample code (you use x twice). For completeness here is the working code.
MockStageRepository2
.Stub(x => x.Single(Arg<System.Linq.Expressions.Expression<Func<Entities.Stage, bool>>>.Matches(y => y.Compile()(StartStage2))))
.Return(StartStage2);