chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
I'm trying to mock a very simple Linq2Sql query
Below is the function I'm trying to test

 public string GetCustomerName(string customerID)
        {
            NorthwindDataContext context=new NorthwindDataContext();

            var customer = from c in context.Customers
                                where c.CustomerID == customerID
                                select c;
            return customer.ElementAt(0).ContactName;
        }


And here's the test function

[TestMethod(),VerifyMocks]
        public void TestingTest()
        {
            var fakeCustomer = new Customer() { CustomerID = "123", ContactName = "Me" };
            var fakeCustomers = new List<Customer>() {fakeCustomer};
            using (RecordExpectations r=new RecordExpectations())
            {
                NorthwindDataContext context = new NorthwindDataContext();

                var customer = from c in context.Customers
                                     where c.CustomerID == "1"
                                     select c;

                r.Return(fakeCustomers.AsQueryable());

            }

            CustomerController target = new CustomerController(); 
            string customerID = "123"; 
            string expected = "me"; 
            string actual;
            actual = target.GetCustomerName(customerID);
            Assert.AreEqual(expected, actual);
        }


When I run test method, I get the following error

Cannot return a value for Queryable.Where() because no value was set. use recorder.Return().

Any ideas?
________
NO2 VAPORIZER
asked by wessamzeidan (720 points)

7 Answers

0 votes
H Wessam,

There are few things that went wrong here.
The first one is caused by the following line :
r.Return(fakeCustomers.AsQueryable());

You must remember that ALL calls inside a recording blocks are mocked including in this case the call to AsQueryable(). To fix you will need to take that statement outside the recording block (I’ve put it on the creation of the fakeCustomers instance)

The next that goes wrong, is caused by the compiler in conjunction with the recording mechanism.
What we see as a simple LINQ query is actually "translated" (during compilation) by the compiler into a very complex piece of code.
In order for the Isolator framework to properly function the LINQ statement during the recording phase must be IDENTICAL to the one which is actually executed.
In our case, there is a small difference on this line:
where c.CustomerID == "1"

It appears that using a string literal and using a string variable is treated differently by the compiler, which in turn confuses the Isolator framework.
To bypass this you just need to define a string variable before the recording block set its value to "1" and then use it during the recording. (On our side we still need to think how to deal with this)


That last thing I have encountered, relates to the current implementation of CustomerController class that you have previously sent me. (I thought on mentioning it here cause it kind of confused me and I wanted to save you that pain). In that implementation, an instance of NorthwindDataContext object is created during the construction of the CustomerController Class . This creation conflicts with the creation you do in the GetCustomerName we have in this example.

What left me at the end with this test (I also remarked the entire BaseController constructor)
[TestMethod(),VerifyMocks] 
public void TestingTest() 
{ 
    var fakeCustomer = new Customer() { CustomerID = "123", ContactName = "Me" };
    var fakeCustomers = (new List<Customer>() { fakeCustomer });
    string Lior = "1";
    using (RecordExpectations r=new RecordExpectations()) 
    { 
        NorthwindDataContext context = new NorthwindDataContext(); 
        var customer = from c in context.Customers
                       where c.CustomerID == Lior 
                       select c;

        r.Return(fakeCustomers.AsQueryable()); 
    } 

    CustomerController target = new CustomerController(); 
    string customerID = "123"; 
    string expected = "Me"; 
    string actual; 
    actual = target.GetCustomerName(customerID); 
    Assert.AreEqual(expected, actual); 
} 

which passes on my side.

Last thing, I just want to verify that last week you received an email from regarding a similar LINQ issue you reported. if you didn’t please let me know.
answered by lior (13.2k points)
0 votes
Hi Lior,
Thanks for the reply. I did the changes that you told me regarding the example I provided in the post, and it worked, but I had to add recorder.RepeatAlways() for it to pass

 [TestMethod(),VerifyMocks]
        public void TestingTest()
        {
            var fakeCustomer = new Customer() { CustomerID = "123", ContactName = "Me" };
            var fakeCustomers = new List<Customer>() {fakeCustomer}.AsQueryable();
          
            string customerID = "1";
            using (RecordExpectations r=new RecordExpectations())
            {
                NorthwindDataContext context = new NorthwindDataContext();
                var customer = from c in context.Customers
                               where c.CustomerID == customerID
                               select c;
                
                r.Return(fakeCustomers);
                r.RepeatAlways();
            }

            CustomerController target = new CustomerController(); 
            string cID = "123"; 
            string expected = "Me"; 
            string actual;
            actual = target.GetCustomerName(cID);
            Assert.AreEqual(expected, actual);
        }


Regarding the emails, the last email I sent had an attachment with a sample project on how my classes are setup. I didn't get a reply about it. Still trying to figure out how to go on making it pass.
answered by wessamzeidan (720 points)
0 votes
Hi Wessam,

Im not sure why do you need the RepeatAlways (on my side it worked without it). In any case I will look into this.

on the other issues you have mailed me, Ive answered those some time ago. It appears that the you did not receive the answer. in anycase ive mailed you again if possible please let me know if you dont get that one as well.
answered by lior (13.2k points)
0 votes
Thanks Lior, I got your email, and I managed to make the test pass.
I have another issue now, mocking linq queries with joins. Any recommendations on how to approach such queries?

For example, in the function above, if you add a join to the query, the test would fail. Any ideas?
________
280
answered by wessamzeidan (720 points)
0 votes
Hi Wessam,

I'm glad we're over that obstacle.
Can you post the entire recording block including the query with the join?
It would be very helpful.

Thanks,
answered by gilz (14.5k points)
0 votes
A very simple example

Method:

 public string GetCustomerName(string customerID)
        {
            NorthwindDataContext context=new NorthwindDataContext();

            var customer= (from cc in context.Customers
                            join o in context.Orders on cc.CustomerID equals o.CustomerID
                            where cc.CustomerID == customerID
                            select cc).SingleOrDefault();
            return customer.ContactName;
        }


Test Method:

[TestMethod()]
        [VerifyMocks]
        public void GetCustomerNameTest()
        {
            var fakeCustomer = new Customer() {CustomerID = "123", ContactName = "Me"};
            
            string customer = "123";
            using(RecordExpectations r=new RecordExpectations())
            {
                NorthwindDataContext context = new NorthwindDataContext();
               var c = (from cc in context.Customers
                        join aa in context.Orders on cc.CustomerID equals aa.CustomerID
                     where cc.CustomerID == customer 
                     select cc).SingleOrDefault();
                r.Return(fakeCustomer);
            }

            CustomerController target = new CustomerController();
            const string customerID = "123";
            string expected = "Me";
            string actual = target.GetCustomerName(customerID);
            Assert.AreEqual(expected, actual);
          
        }

________
silver surfer review
answered by wessamzeidan (720 points)
0 votes
Hi Wessam,

Thanks. These LINQ queries are a challenge, as we're discovering what the compiler has for us underneath the covers. :P

We'll get back once we have updates on the issue.
answered by gilz (14.5k points)
...