Error when trying to test an isolated IQueryable - c#

Context:
I want to test whether a piece of code that purports to layer some operations on top of an IQueryable<T> actually does so. But when I start with code that is known to work, and try to write a test to exercise it, I get an unintelligible error.
Actual Question:
I would like to understand that error, what it means, and why it is happening.
Not an X-Y questions!!
I'm not interested here in what the best way to achieve my original goal is, or whether this test would have achieved it. I'm asking that question separately (link). In this question, I genuinely want to know "what does this error even mean, and why is it happening for code that I know fundamentally works".
Error Message:
System.ArgumentException : Expression of type '' cannot be used for parameter of type
'System.Linq.IQueryable`1[ADH.Web.API.Tests.Services.QueryableTest+DemoDomainModel]' of method
'System.Linq.IQueryable`1[ADH.Web.API.Tests.Services.QueryableTest+DemoViewModel]
Select[DemoDomainModel,DemoViewModel](System.Linq.IQueryable`1[ADH.Web.API.Tests.Services.QueryableTest+DemoDomainModel],
System.Linq.Expressions.Expression`1[System.Func`2[ADH.Web.API.Tests.Services.QueryableTest+DemoDomainModel,ADH.Web.API.Tests.Services.QueryableTest+DemoViewModel]])'
at System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi)
at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments)
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
at System.Linq.Queryable.Select[TSource,TResult](IQueryable`1 source, Expression`1 selector)
at ADH.Web.API.Tests.Services.QueryableTest.DemoService.GetAllDemoViewModels() in C:\Work\ADH\ADH\Actuarial Data Hub\ADH.Web.API.Tests\Services\QueryableTest..cs:line 50
at ADH.Web.API.Tests.Services.QueryableTest.CheckQueryableCompiles() in C:\Work\ADH\ADH\Actuarial Data Hub\ADH.Web.API.Tests\Services\QueryableTest..cs:line 71
Simplification of first line:
System.ArgumentException : Expression of type '' cannot be used for parameter of type
'IQueryable`1[DemoDomainModel]' of method
'IQueryable`1[DemoViewModel] Select[DemoDomainModel,DemoViewModel]
(IQueryable`1[DemoDomainModel], Expression`1[Func`2[DemoDomainModel,DemoViewModel]])'
Code and Test that causes the bug (Classes + unit Test)
using System.Linq;
using NUnit.Framework;
using FakeItEasy;
namespace ADH.Web.API.Tests.Services
{
public class QueryableTest
{
public class DemoDomainModel
{
public int Id { get; set; }
public string Reference { get; set; }
public int ChildId { get; set; }
public DemoChildDomainModel Child { get; set; }
}
public class DemoChildDomainModel
{
public int Id { get; set; }
public string ChildReference { get; set; }
}
public class DemoViewModel
{
public int Id { get; set; }
public string Reference { get; set; }
public string ChildReference { get; set; }
}
public interface IDemoRepository
{
IQueryable<DemoDomainModel> GetAllDemos();
}
public class DemoService
{
private readonly IDemoRepository _demoRepository;
public DemoService(IDemoRepository configRepository)
{
_demoRepository = configRepository;
}
public IQueryable<DemoViewModel> GetAllDemoViewModels()
{
var demos = _demoRepository.GetAllDemos();
return demos.Select(demo => new DemoViewModel()
{
Id = demo.Id,
Reference = demo.Reference,
ChildReference = demo.Child.ChildReference
});
}
}
private DemoService _demoService;
private IDemoRepository _fakeDemoRepository;
[SetUp]
public void Setup()
{
_fakeDemoRepository = A.Fake<IDemoRepository>();
_demoService = new DemoService(_fakeDemoRepository);
}
[Test]
public void CheckQueryableCompiles()
{
_demoService.GetAllDemoViewModels();
}
}
}

Related

How to create fluent methods with 2 Generic Types?

I have the following classes (omitted properties for sake of simplicity):
public class Person {
public Address Address { get; set; }
public Hobby Hobby { get; set; }
}
public class Address {
public Country Country { get; set; }
}
public class Country { }
public class Hobby { }
And I created an IncludeMapper to be used, if possible, as follows:
IncludeMapper<Person> m = IncludeMapper
.For<Person>()
.Add(person => person.Address).And(address => address.Country)
.Add(person => person.Hobby);
Add will take the base type, e.g, Person.
And will take the type used in the previous Add or And.
public class IncludeMapper {
public static IncludeMapper<T> For<T>() {
return new IncludeMapper<T>();
}
}
public class IncludeMapper<T> {
public IncludeMapper<T> Add<K>(String expression, Expression<Func<T, K>> property) {
return this;
}
public IncludeMapper<K> And<K>(String expression, Expression<Func<T, K>> property) {
return this;
}
}
This won't work ... I think I need to return on the methods and I might need an extra class because the For is only for T?
Could someone help me out with this?

Moq - Setup mocked object using Generic functions for a unit test

In an attempt to follow the DRY (Don't Repeat Yourself) principle in my unit tests I am trying to create a generic unit test that will perform the same test on several methods that all return an object which share the same interface. However, I cannot seem to find a way to create a mock.Setup for the methods in the generic method. Examples are as follows:
Here are the class Implementations:
public class RootClass
{
public Foo Foo { get; set; }
}
public class Foo
{
public Bar1 Method1(int x)
{
var bar = new Bar1();
// do stuff //
return bar;
}
public Bar2 Method2(string str)
{
var bar = new Bar2();
// do stuff //
return bar;
}
}
public interface IBar
{
string Message { get; set; }
bool Success { get; set; }
Exception ex { get; set; }
}
public class Bar1 : IBar
{
public string Result { get; set; }
public Exception ex { get; set; }
public string Message { get; set; }
public bool Success { get; set; }
}
public class Bar2 : IBar
{
public int Result { get; set; }
public Exception ex { get; set; }
public string Message { get; set; }
public bool Success { get; set; }
}
Here are the test implementations:
private static RootClass systemUnderTest;
private static Mock<IFoo> FooMock;
[TestInitialize]
public void Setup()
{
FooMock = new Mock<IFoo>();
systemUnderTest = new RootClass();
systemUnderTest.Foo = FooMock.Object;
}
[TestMethod]
public void Method1_Bar1SuccessIsTrue()
{
//FooMock.Setup(x => x.Method1(It.IsAny<int>())).Returns(new Bar1); <~~~~This is the Moq Setup I would like to move into the generic method
AssertBarSuccessIsTrue<int, Bar1>(systemUnderTest.Bar1, FooMock.Object.Bar1);
}
[TestMethod]
public void Method2_Bar2SuccessIsTrue()
{
//FooMock.Setup(x => x.Method2(It.IsAny<string>())).Returns(new Bar2);
AssertBarSuccessIsTrue<string, Bar2>(systemUnderTest.Bar2, FooMock.Object.Bar2)
}
private void AssertBarSuccessIsTrue<PARAM, BAR>(Func<PARAM, BAR> f, Func<PARAM, IBAR> task) where BAR : IBAR where PARAM : new()
{
FooMock.Setup(x => task); <~~~Throws an ArgumentException; no doubt because of the missing lambda expression.
PARAM parameter = new PARAM();
BAR bar = f.Invoke(parameter);
Assert.IsTrue(bar.Success);
}
I have tried to make this work through several attempts including creating an argument for the lambda expression, creating an argument for the It.IsAny<>() expression, creating delegates for the specified method under test. However, every attempt either creates a compiler error or throws a runtime exception.
I can create the generic test if I do a setup in every test (as seen in the commented out .Setup lines). However does anyone have an idea how I can move that setup line into the generic method? I know its only one line, but it seem to me this should be possible.

Setting nested properties via an Expression

I have the following object:
public class ContactImport {
public long Id {get;set;}
public Contact Contact {get;set;}
public Company Company {get;set;}
public Address Address {get;set;}
}
I want to be able to set the properties on the the nested objects dynamically based on an expression passed in (Expression<Func<T, dynamic>>).
To do this I have the following method, this works fine for setting properties on the top level object (such as Id) but fails when trying to set anything on the nested objects (such as Contact.FirstName)
public static void SetPropertyValue<T, TProp>(this T target, Expression<Func<T, TProp>> member, TProp value) {
var selectorExpr = (MemberExpression)(member.Body is UnaryExpression ? ((UnaryExpression)member.Body).Operand : member.Body);
if (selectorExpr != null) {
var property = selectorExpr.Member as PropertyInfo;
if (property != null) {
property.SetValue(target, value);
}
}
}
It looks like it's trying to set the property on the top level object but can't. I take it this is possible but I'm unsure how to achieve it with what I currently have.
The SetPropertyValue method is invoke like this:
public class ImportCheck<T> {
public int id { get; set; }
public string Name { get; set; }
public Type Type { get; set; }
public bool Required { get; set; }
public int? MinLength { get; set; }
public int? MaxLength { get; set; }
public string Value { get; set; }
public Expression<Func<T, dynamic>> AssociatedProperty { get; set; }
}
T pt = (T)Activator.CreateInstance(typeof(T));
foreach (var m in mapping) {
pt.SetPropertyValue(m.AssociatedProperty, Convert.ChangeType(m.Value, Nullable.GetUnderlyingType(m.Type) ?? m.Type));
}
In the above example T is ContactImport, m.AssociatedProperty is the expression and mapping is a List<ImportCheck<ContactImport>>.
Update
My issue seems to boil down to the fact that the expression being passed into SetPropertyValue has a return type of dynamic. If this is set to int and the property on the nested object is an int then it all works. The problem I have then is that I need to explicitly set the result of the expression to match the type of the target property. This however leaves me with another issue in that I need a list of ImportChecks with the possibility of each Expression<Func<T,dynamic>> having a different return type.

How can I query different tables dynamically with LINQ?

So I'm not sure if you can do this or not, but I would like to avoid using SQL strings if I can. What I would like to do with Linq/DbContexts is the following that can be done easily with SQL:
string sql = "UPDATE " + tableName + " SET Status=0 WHERE Id=" + formId.ToString();
I can easily put this into a loop where tableName and formId are given dynamically and execute no problem.
I have multiple DbContexts, so I don't know of any way to do something like:
var db = new *dynamicallyChosenContext*()
var query = from p in db.*dynamicallyChosenAlso*
where p.Id == formId
select p;
foreach (var result in query)
{
result.Status = 0;
}
db.SaveChanges()
Thanks for the help!
Here is a piece of working code that can update different tables at runtime from different contexts without using reflection.
namespace DemoContexts
{
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
public interface IThing
{
int Id { get; set; }
int Status { get; set; }
}
public class FirstPersonThing : IThing
{
[System.ComponentModel.DataAnnotations.Key]
public int Id { get; set; }
public int Status { get; set; }
public string Foo { get; set; }
}
public class SecondPersonThing : IThing
{
[System.ComponentModel.DataAnnotations.Key]
public int Id { get; set; }
public int Status { get; set; }
public string Bar { get; set; }
}
public class FirstContext : DbContext
{
public FirstContext() : base("FirstContext") { }
public DbSet<FirstPersonThing> MyThings { get; set; }
public DbSet<SecondPersonThing> YourThings { get; set; }
}
public class SecondContext : DbContext
{
public SecondContext() : base("SecondContext") { }
public DbSet<FirstPersonThing> MyThings { get; set; }
public DbSet<SecondPersonThing> YourThings { get; set; }
}
class Program
{
static void Main(string[] args)
{
int contextType = 1;
int thingType = 1;
DbContext db = RunTimeCreatedContext(contextType);
IQueryable<IThing> collection = RunTimeCreatedCollection(db, thingType);
UpdateRuntimeDeterminedThings(db, collection, 1);
Console.ReadLine();
}
public static void UpdateRuntimeDeterminedThings(DbContext db,
IQueryable<IThing> collection,
int formId)
{
var querySet = collection.Where(p => p.Id == formId).ToList();
foreach (var result in querySet)
{
result.Status = 0;
}
db.SaveChanges();
}
static DbContext RunTimeCreatedContext(int contextType)
{
if (contextType == 0)
{
return new FirstContext();
}
else
{
return new SecondContext();
}
}
static IQueryable<IThing> RunTimeCreatedCollection(DbContext db, int thingType)
{
if (thingType == 0)
{
return db.Set(typeof(FirstPersonThing)) as IQueryable<IThing>;
}
else
{
return db.Set<SecondPersonThing>();
}
}
}
}
The first thing to note is that all this is statically typed so to perform a generic query against different types of objects these objects must have common property signatures and this conceptually is expressed in the IThing interface.
A second thing to note is how the IQueryable is generated. It is generated by the DbContext.Set Method (Type) in the first instance (for the FirstPersonThings), it is generated by the DbContext.Set<TEntity> Method in the second instance. The first uses a type determined at runtime and requires a cast (but could be useful to use passing types at runtime), the second uses generics and the types are determined at compile time. There are obviously a number of other ways that this function could work.
Finally the method UpdateRuntimeDeterminedThings works because it uses properties and methods that are shared across the types (either with base types/inheritance or by the implementation of interfaces).
None of this is actually dynamic programming (which is possible using the dynamic type) and I have used the term runtime determined rather than dynamic to describe how this works.
There is a technique in functional programming, called Currying, where you could pass as much parameters as you want, so you are able to access them.
Here is an exemple: http://blogs.msdn.com/b/sriram/archive/2005/08/07/448722.aspx
P.S: You could use a currying function to iterate through yours DBContexts.
I think you have to use reflection if you want to use 'code' and not sql strings. That's just how C# works... This is how you could do it:
using System;
using System.Data.Entity;
using System.Linq;
public class TestContext : DbContext
{
public DbSet<Box> Boxes { get; set; }
public DbSet<Thing> Things { get; set; }
}
public abstract class Base
{
public int Id { get; set; }
}
public class Box : Base
{
public string Title { get; set; }
}
public class Thing : Base
{
public string Name { get; set; }
}
internal class Program
{
private static void Main(string[] args)
{
var db = new TestContext();
DoIt(GetPropValue(db, "Boxes") as IQueryable<Base>);
DoIt(GetPropValue(db, "Things") as IQueryable<Base>);
}
private static void DoIt(IQueryable<Base> b)
{
Console.WriteLine(
b.Single(t => t.Id == 1).Id);
}
private static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
}
Obviously you can then put the strings in a list etc, whatever you need.

C#: specialized template method - Error: Type '...' already defines a member called '...' with the same parameter types

I'm quite new to C# and currently developing an application using the EntityFramework. I would like to extend the functionality of the database context class, so that I can call a method getPool() so that it hands out the according DbSet member of the class.
I need to implement it as a template as it will be later called from other templates, which are just knowing about the (global) database context object and a type T (having a given superclass) for which they shall query the database.
Here is what I tried (a bit simplified - original example is too complicated):
public class TestContext : DbContext
{
public DbSet<TestA> ATests { get; set; }
public DbSet<TestB> BTests { get; set; }
public IQueryable<T> getPool<T>() where T : TestA {
return (IQueryable<T>)ATests;
}
public IQueryable<T> getPool<T>() where T : TestB {
return (IQueryable<T>)BTests;
}
}
The error message is
Error: Type '...' already defines a member called '...' with the same parameter types.
And it occurs at the line of the second specialized definition of my template (public IQueryable<T> getPool<T>() where T : TestB).
The question is: How to fix this?
Unfortunately, in C#, you cannot overload a method by using a generic type constraint like this. You will have to give them different names like this
public class TestContext : DbContext
{
public DbSet<TestA> ATests { get; set; }
public DbSet<TestB> BTests { get; set; }
public IQueryable<T> getPoolA<T>() where T : TestA {
return (IQueryable<T>)ATests;
}
public IQueryable<T> getPoolB<T>() where T : TestB {
return (IQueryable<T>)BTests;
}
}
Another solution would be to do something like this:
public class TestContext : DbContext
{
public DbSet<TestA> ATests { get; set; }
public DbSet<TestB> BTests { get; set; }
public IQueryable<T> getPool<T>() {
return (typeof(T) == typeof(TestA))
? (IQueryable<T>)ATests
: (IQueryable<T>)BTests;
}
}
Now, you can make this even cleaner, since IQueryable<T> is covariant in T, you can avoid casting:
public class TestContext : DbContext
{
public DbSet<TestA> ATests { get; set; }
public DbSet<TestB> BTests { get; set; }
public IQueryable<T> getPool<T>() {
return (typeof(T) == typeof(TestA)) ? ATests : BTests;
}
}
If you want to avoid testing for types you can do something like this:
public class TestContext : DbContext
{
readonly Dictionary<Type, object> _sets;
public DbSet<TestA> ATests { get; set; }
public DbSet<TestB> BTests { get; set; }
public TestContext()
{
_sets = new Dictionary<Type, object>
{
{ typeof(TestA), ATests },
{ typeof(TestB), BTests }
}
}
public IQueryable<T> getPool<T>() {
return (IQueryable<T>)_sets[typeof(T)];
}
}
I'd recommend (besides of reading about generics and C# in general) to configure the pool with desired types on run time, store them in dictionaries and use the Type as key, i.e. something along the following lines...:
//...
// configuration, maybe factor out to a dedicated class...
private readonly IDictionary<System.Type, IQueryable> m_SupportedPools =
new Dictionary<System.Type, IQueryable>();
// add this queryable, note that type inference works here
public void AddToPool<T>(IQueryable<T> p_Queryable)
{
m_SupportedPools.Add(typeof(T), p_Queryable);
}
public IQueryable<T> GetPool<T>()
{
IQueryable t_Set = null;
if (m_SupportedQueries.TryGetValue(typeof(T), out t_Set)) {
return t_Set as IQueryable<T>;
} else {
return null;
}
}

Categories

Resources