I have a repository that exposes IQueryable and a service handles specific queries and here a few methods that make use of DbFunctions. In order to be testable, i create a fake repository with static list of elements and inject it into the service. Problem is, since my service queries a List and does not make use of database, i get the error "This function can only be invoked from LINQ to Entities.".
Is there any easier way for testing this than creating a fake DbFunctions and QueryProvider?
Thanks in advance
I'm tried to implement dateDiff function, and it's works for me
but we should think that in that case we test different functions
and we are testing not real behaviour
private class MySqlFunctions
{
[DbFunction("SqlServer", "DATEDIFF")]//EF will use this function
public int? DateDiff(string datePartArg, DateTime startDate, DateTime endDate)
{
var subtract = startDate.Subtract(endDate);
switch (datePartArg)
{
case "d":
return (int?)subtract.TotalDays;
case "s":
return (int?)subtract.TotalSeconds; // unit test will use this one
}
throw new NotSupportedException("Method supports only s or d param");
}
}
Then in linq code
var sqlFunctions = new MySqlFunctions();
var result = matches.Average(s => sqlFunctions.DateDiff("s", s.MatchCreated, s.WaitingStarted);
You can't reliably fake SQL due to the fact that LINQ to objects behaves differently in many cases than LINQ to SQL. For example, where (new [] { "asdf"}).Contains("ASDF") returns false in LINQ to objects, the same type of query in LINQ to SQL would return true. The best thing I've found to do is to separate the retrieval of data from the action on that data. Maybe create some kind of PersonManager that takes an IPersonRepository as a dependency. You can fake/mock IPersonRepository and use that to test that PersonManager does what it's supposed to do under various circumstances.
since i hit the same problem recently, and opted for a simpler solution, wanted to post it here.. this solution requires no Shims, Mocking, nothing expansive etc.
Pass a 'useDbFunctions' boolean flag to your method with default value as true.
When your live code executes, your query will use DbFunctions and everything will work. Due to the default value, callers need not worry about it.
When your unit tests invoke the method to test, they can pass useDbFunctions: false.
In your method, you can make use the flag to compose your IQueryable..
if useDbFunctions is true, use the DbFunctions to add the predicate to the queryable.
if useDbFunctions is false, then skip the DbFunctions method call, and do an explicit C# equivalent solution.
This way, your unit tests will check almost 95% of your method in parity with live code. You still have the delta of "DbFunctions" vs. your equivalent code, but be diligent about it and the 95% will look like a lot of gain.
public SomeMethodWithDbFunctions(bool useDbFunctions = true)
{
var queryable = db.Employees.Where(e=>e.Id==1); // without the DbFunctions
if (useDbFunctions) // use the DbFunctions
{
queryable = queryable.Where(e=>
DbFunctions.AddSeconds(e.LoginTime, 3600) <= DateTime.Now);
}
else
{
// do db-functions equivalent here using C# logic
// this is what the unit test path will invoke
queryable = queryable.Where(e=>e.LoginTime.AddSeconds(3600) < DateTime.Now);
}
var query = queryable.Select(); // do projections, sorting etc.
}
Unit tests will invoke the method as:
SomeMethodWithDbFunctions(useDbFunctions: false);
Because unit tests would have setup local DbContext entities, the C# logic/DateTime functions would work.
Related
I have a project with a large codebase that uses an in-house data access layer to work with the database. However, we want to support OData access to the system. I'm quite comfortable with expression trees in C#. How do I get at something I can parse here in order to get the structure of their actual query?
Is there a way to get an AST out of this thing that I can turn into sql code?
Essentially, you need to implement you own Query Provider which known how to translate the expression tree to an underlying query.
A simplified version of a controller method would be:
[ODataRoute("foo")]
public List<Foo> GetFoo(ODataQueryOptions<Foo> queryOptions)
{
var queryAllFoo = _myQueryProvider.QueryAll<Foo>();
var modifiedQuery = queryOptions.ApplyTo(queryAllFoo);
return modifiedQuery.ToList();
}
However!
This is not trivial, it took me about 1 month to implement custom OData query processing
You need to build the EDM model, so the WebApi OData can process and build right expression trees
It might involve reflection, creation of types at runtime in a dynamic assembly (for the projection), compiling lambda expressions for the best performance
WebAPI OData component has some limitations, so if you want to get relations working, you need to spend much more extra time, so in our case we did some custom query string transformation (before processing) and injecting joins into expression trees when needed
There are too many details to explain in one answer, it's a long way..
Good luck!
You can use ODataQueryOptions<T> to get abstract syntax trees for the $filter and $orderby query options. ($skip and $top are also available as parsed integers.) Since you don't need/want LINQ support, you could then simply pass the ASTs to a repository method, which would then visit the ASTs to build up the appropriate SQL stored proc invocation. You will not call ODataQueryOptions.ApplyTo. Here's a sketch:
public IEnumerable<Thing> Get(ODataQueryOptions<Thing> opts)
{
var filter = opts.Filter.FilterClause.Expression;
var ordering = opts.OrderBy.OrderByClause.Expression;
var skip = opts.Skip.Value;
var top = opts.Top.Value;
return this.Repository.GetThings(key, filter, ordering, skip, top);
}
Note that filter and ordering in the above are instances of Microsoft.OData.Core.UriParser.Semantic.SingleValueNode. That class has a convenient Accept<T> method, but you probably do not want your repository to depend on that class directly. That is, you should probably use a helper to produce an intermediate form that is independent of Microsoft's OData implementation.
If this is a common pattern, consider using parameter binding so you can get the various query options directly from the controller method's parameter list.
I am writing a simple file converter which will take an XML file and convert it to CSV or vice-versa.
I have implemented 2 classes, XMLtoCSV and CSVtoXML and both implement a Convert method which takes the input file path and filter text and filters the XML by the given filter and performs the conversion. (e.g if the XML contains employee details, we might want to filter it so only employees from a certain department is retrieved and converted to CSV file).
I have a unit test which tests this Convert method. In it I am specifying the input file path and filter string and call the Convert function and assert the boolean result but I also need to test if the filtering worked and conversion has been completed.
My question is that do you really need to access the file IO and do the filtering and conversion via unit test? Is this not integration testing? If not then how can I assert the filtering has worked without actually converting the file and returning the results? I thought about Moq'ing the Convert method, but that will not necessarily prove that my Convert method is working fine.
Any help/advice is appreciated.
Thanks
I will suggest you to use streams in your classes and pass file stream in application and a "fake" or StringStream, for example, in unit tests. This will makes you more flexible in case you will decide to get this xml from WebService or any other way - you will just need to pass a stream, not file path.
My question is that do you really need to access the file IO and do
the filtering and conversion via unit test? Is this not integration
testing?
Precisely - in this case you are testing 3 things - the File IO system, the actual file contents, and the Convert method itself.
I think you need to look at restructuring your code to make it more amenable to unit testing (that's not a criticism of your code!). Consider your definition of the Convert method:
In it I am specifying the input file path and filter string
So your Convert method is actually doing two things - opening/reading a file, and converting the contents. You need to change things around so that the Convert method does one thing only - specifically, perform the conversion of a string (or indeed a stream) without having any reference to where it came from.
This way, you can correctly test the Convert method by supplying it with a string that you define yourself in your unit test - One test with known good data,and one with known bad data.
e.g.
void Convert_WithGoodInput_ReturnsTrue()
{
var input="this is a piece of data I know is good and should pass";
var sut = new Converter(); //or whatever it's called :)
bool actual = sut.Convert(input);
Assert.AreEqual(true,actual,"Convert failed to convert good data...");
}
void Convert_WithBadInput_ReturnsFalse()
{
var input="this is a piece of data I know is BAD and should Fail. Bad Data! Bad!";
var sut = new Converter(); //or whatever it's called :)
bool actual = sut.Convert(input);
Assert.AreEqual(false,actual,"Convert failed to complain about bad data...");
}
Of course inside your Convert method you are doing all sorts of arcane and wonderful things and at this point you might then look at that method and see if perhaps you can split it out into several internal methods, the functionality of which is perhaps provided by separate classes, which you provide as dependencies to the Converter class, and which in turn can all be tested in isolation.
By doing this you will be able to test both the functionality of the converter method, and you will be in a position to start using Mocks so that you can test the functional behaviour of it as well - such as ensuring that the frobber is called exactly once, and always before the gibber, and that the gibber always calls the munger, etc.
Bonus
But wait, there's more!!!!1!! - once your Converter class/method is arranged like this you will suddenly find that you can now implement an XML to Tab-delimited, or XML to JSON, or XML to ???? simply by writing the relevant component and plugging it into the Converter class. Loose coupling FTW!
e.g (and here I am just imagining how the guts of your convert function might work)
public class Converter
{
public Converter(ISourceReader reader, IValidator validator, IFilter filter,IOutputformatter formatter)
{
//boring saving of dependencies to local privates here...
}
public bool Convert(string data,string filter)
{
if (!validator.Validate(data)) return false;
var filtered = filter.Filter(data);
var raw = reader.Tokenise(filtered);
var result = formatter.Format(raw);
//and so on
return true; //or whatever...
}
}
Of course I am not trying to tell you how to write your code but the above is a very testable class for both unit and functional testing, because you can mix and match Mocks, Stubs and Reals as and where you like.
The following method works properly in my service layer:
public override IList<City> GetAll()
{
var query = from item in _tEntities
select item;
query.Load();
return _tEntities.Local;
}
but when i try to run following method, the method returns old data loaded by GetAll() method.
public override IList<City> GetAll(Func<City, bool> predicate)
{
var query = from item in _tEntities
select item;
query.Where<City>(predicate);
query.Load();
return _tEntities.Local;
}
What is the problem and how can i fix them?
How can i use local method in this sample and reload new data into local(cache)?
You are looking at the wrong problem. What you are most likely seeing is a result of the fact that when you do the first query, the local cache is empty. So it only returns the results from your query. But when you do the second, it's returning the results of your first query AND your second query.
This comes down to the fact that you are using a shared DbContext between all your methods. Local contains a cache of all records the context has retrieved, not just the most recent query.
The correct solution is to not use Local in this manner. Even better, don't use a shared context since this can lead to context cache bloat.
I'm not too sure what you are trying to achieve with a .Load method here but it seems like you want the following.
public override IList<City> GetAll(Func<City, bool> predicate)
{
return _tEntities.Where<City>(predicate).ToList();
}
query.Where<City>(predicate);
This doesn't change query. The query.Load() on the next line ignores the predicate: you're calling query.Load() and not query.Where<City>(predicate).Load(). It's as if you had written
int i = 3;
i + 1;
Console.WriteLine(i); // still prints 3
In that example, C# does not really actually allow an addition to be used as a statement, but .Where(predicate) is a method call, and method calls can be used as such, even if they return values.
This is not your only issue (see the other answers), but my guess is that this issue is the one that leads to the unexpected results you're seeing.
Forgive me if this is a stupid question, but I'm fairly new at mocking, and am trying to get my head around it.
I have some unit tests (using the built-in Visual Studio 2010 Professional testing features), which use a stub that is needed by a method. I created a stub, and set the default return values for a couple of properties and a method, and all works well. I have a static class that sets up the stub, and this is used in the TestInitialize method to set up the stub...
public static AppointmentReminderProviderInterface GetMockProvider() {
AppointmentReminderProviderInterface provider = MockRepository.GenerateStub<AppointmentReminderProviderInterface>();
provider.Stub(p => p.ContactName).Return(MockProviderContactName);
provider.Stub(p => p.ContactEmail).Return(MockProviderContactEmail);
return provider;
}
Note that MockProviderContactName and MockProviderContactEmail are local string properties that contain default data for the provider. The unit tsts that check to see if things work as expeced with the default data all pass fine.
However, I now want to test what happens when one of these properties contains duff data. I thought I could just set this on the stub, but it isn't working. The test method contains the following lines...
_provider.Stub(p => p.ContactEmail).Return("invalid");
Debug.WriteLine("Provider email: <" + _provider.ContactEmail + ">");
The Debug.WriteLine() shows me that, despite the fact that I have set the ContactEmail property to return "invalid" it still returns the default email address. This causes my test to fail, as I'm expecting it to throw an exception, and it doesn't.
Anyone any idea why I can't change the return value of this property?
Thanks for any help.
As a tricky but working solution I'd suggest to use Do handler here. It allows to implement some logic for stubbed method/property.
See example:
var providerContactEmail = "Email1";
provider
.Stub(p => p.ContactEmail)
.Do((Func<string>)(() => providerContactEmail));
// here provider.ContactEmail returns "Email1"
providerContactEmail = "Email2";
// now provider.ContactEmail returns "Email2"
But in my opinion it is much better if the solution can be found which allows to don't change return value in the middle of test. :)
Try changing
_provider.Stub(p => p.ContactEmail).Return("invalid");
To
_provider.ContactEmail = "invalid";
Assuming ContactEmail has a setter, this should work. If this doesn't resolve your issue, I'd follow Alexander Stepaniuk's advice and refactor your test so that you're not adding multiple behaviors for the same stub; I think that has something to do with your issue.
I have the following method:
User IDataContext.AuthenticateUser(string userName, string password)
{
byte[] hash = PasswordHasher.HashPassword(userName, password);
var query =
from e in mContext.GetTable<User>()
where e.Email == userName && e.Password == hash
select e;
return query.FirstOrDefault();
}
When mContext is a System.Data.Linq.DataContext everything works great. However, when mContext is an in-memory mock during my uniting testing, the comparison between e.Password and hash always returns false.
If I rewrite this comparison as e.Password.SequenceEqual(hash), then my unit tests will pass, but I get an exception when I'm talking to LinqToSql. (System.NotSupportedException: The query operator 'SequenceEqual' is not supported.)
Is there a way that I can write this query that will satisfy my unit tests with an in-memory mock, as well as the production component with LinqToSql?
That's an interesting one. I can't think of a convenient way of intercepting the equals without breaking everything, but: are the user-names unique? You could just include the username condition in the LINQ, then check the hash in regular c#. In terms of data transferred there is little difference between passing it in and fetching it out, especially if we optimise for the success case (in which case this reduces the IO requirements).
Note: return the same result for "not found" and "not a match" if you do this.
Because the byte[] compare no longer depends on special treatment by LINQ-to-SQL, it should work fine in your mock now.
var user = (by name).SingleOrDefault();
if(user==null) #fail
bool hashMatch = /* compare array */
if (!hashMatch) #fail
return user;
This is not a good candidate for unit testing. What value is produced by testing SQL's equality by using .Net's equality?
In psuedocode, I see (in essence) three method calls:
HashPassword();
ConstructQuery();
FirstOrDefault();
Each of these three called methods may be unit tested. What's the point of unit testing the original method?