JustMock LINQ types “Func<>” and “Expression<>”

12 posts, 0 answers
  1. Carlos
    Carlos avatar
    2 posts
    Member since:
    Mar 2005

    Posted 08 Apr 2011 Link to this post

    Hi, I'm trying to unit test a common interface used in a generic Repository, something like T GetWhere(Func<T, Boolean> where)...
    When I set this expectation in a test

    Mock.Arrange(() => bookRepo.GetWhere(book => book.Id == 1))
                     .Returns(expectedBook)
                     .MustBeCalled();

    JustMock throws this exception:  "Telerik.JustMock.MockAssertionException: Setup contains calls that are marked as "MustBeCalled" but actually never called"
    It seems the GetWhere() method was never call, to return the expected object.
    Below is a simple example that illustrate the case.  
    How should I rewrite the second test below so that I can mock and test these type of interfaces? 
    Thanks in advance. 

    using System;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Telerik.JustMock; //Free version 2011.1.331.1
    using Model.Infrastructure;
    using Model;
      
    namespace Model.Infrastructure
    {
        public interface IRepository<T> where T : class
        {
            T GetById(int Id);
            T GetWhere(Func<T, Boolean> where);
        }
    }
      
    namespace Model
    {
        public class Book
        {
            public int Id { get; set; }
            public string BookTitle { get; set; }
            public string OnLoanTo { get; set; }
            public Book(){}
        }
      
        public class BookService
        {
            private IRepository<Book> _bookRepository;
            public BookService(IRepository<Book> bookRepository)
            {
                this._bookRepository = bookRepository;
            }
      
            public Book GetSingleBook1(int bookId)
            {
                return _bookRepository.GetById(bookId);;
            }
      
            public Book GetSingleBook2(int bookId)
            {
                Book b = _bookRepository.GetWhere(x => x.Id == bookId);
                return b;
            }
        }
    }
      
    namespace Model.Tests
    {
        [TestClass]
        public class AssortedTests
        {
            private Book expectedBook;
            private IRepository<Book> bookRepo;
            private BookService bookService;
      
            [TestInitialize]
            public void Setup()
            {
                expectedBook = new Book()
                { Id = 1,
                  BookTitle =
    "Adventures",
                  OnLoanTo =
    "John Smith"
                };
                bookRepo = Mock.Create<IRepository<Book>>();
                bookService = new BookService(bookRepo);
            }
      
            [TestMethod]
            public void Book_CanRetrieveBookFromRepository()
            {
                Mock.Arrange(() => bookRepo.GetById(1))
                                 .Returns(expectedBook)
                                 .MustBeCalled();
                //Act
                Book actualBook = bookService.GetSingleBook1(1); 
      
                Mock.Assert(bookRepo); //Pass...
                Assert.IsTrue(actualBook.BookTitle == "Adventures");
            }
      
            [TestMethod]
            public void Book_CanRetrieverFromRepositoryUsingLambdaExpressions()
            {
                Mock.Arrange(() => bookRepo.GetWhere(book => book.Id == 1))
                                 .Returns(expectedBook)
                                 .MustBeCalled();
                //Act
                Book actualBook = bookService.GetSingleBook2(1);
      
                Mock.Assert(bookRepo); //Throws the error...
                Assert.IsTrue(actualBook.BookTitle == "Adventures");
            }
        }
    }
  2. Ricky
    Admin
    Ricky avatar
    467 posts

    Posted 12 Apr 2011 Link to this post

    Hello Carlos,

    Thanks again for sending the issue. However, you could write the failing test in the following way that will make it work:

    [TestMethod]
    public void Book_CanRetrieverFromRepositoryUsingLambdaExpressions() //Fail...
    {
        Mock.Arrange(() => bookRepo.GetWhere(Arg.IsAny<Func<Book, Boolean>>()))
                         .Returns(expectedBook)
                         .MustBeCalled();
        //Act
        Book actualBook = bookService.GetSingleBook2(1);
     
        Mock.Assert(bookRepo);
        Assert.IsTrue(actualBook.BookTitle == "Adventures");
    }

    But your report is legitimate and seems to be the case for other popular tools as well. Like the one I found in this stackoverflow thread:

    http://stackoverflow.com/questions/5196669/moqing-methods-where-expressionfunct-bool-are-passed-in-as-parameters

    But we would love to implement this as a feature and thanks again for pointing this to us. You can further follow the task in the following PITS entry:

    http://www.telerik.com/support/pits.aspx#/public/justmock/5515


    Kind Regards,
    Mehfuz
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  3. DevCraft R3 2016 release webinar banner
  4. Carlos
    Carlos avatar
    2 posts
    Member since:
    Mar 2005

    Posted 12 Apr 2011 Link to this post

    Thank you for the feedback Mehfuz.
    I found the test also pass if "IgnoreArgument()" is used instead of your proposed workaround:Arg.IsAny<Func<Book, Boolean>>().  In either case, I feel the test is not quite-right as it is ignoring the argument anyway. 

    [TestMethod]
    public void Book_CanRetrieverFromRepositoryUsingLambdaExpressions()
    {
        Mock.Arrange(() => bookRepo.GetWhere(b => b.Id == 1))
                         .IgnoreArguments()//Now it pass, but accepts any argument!
                         .Returns(expectedBook)
                         .MustBeCalled();
        //Act
        Book actualBook = bookService.GetSingleBook2(Arg.IsAny<int>());
     
        Mock.Assert(bookRepo);
        Assert.IsTrue(actualBook.BookTitle == "Adventures");
    }

    I'm glad this Mocking methods where Expression<Func<T, bool>> are passed in as parameters is going to be implemented as a feature for the product.  Great!
  5. Ricky
    Admin
    Ricky avatar
    467 posts

    Posted 13 Apr 2011 Link to this post

    Hello Carlos,

    Thanks again for your reply. Yes you are right that you can use IgnoreArguments as well instead of Arg.IsAny<Func<Book, Boolean>>(). Sorry that i forgot to mention it. Also, its great that you pointed this Mocking methods where Expression<Func<T, bool>> are passed in as parameters out.

    Should you have any more issues , please don't hesitate to write us back.

    Kind regards,
    Mehfuz
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  6. Josh
    Josh avatar
    6 posts
    Member since:
    Apr 2012

    Posted 17 Jan 2013 Link to this post

    I apologize for bringing up an old issue, but is there a way to use Arg.Matches on an Expression/Func?  I could not find any other posts that refer to matching on an Expression for an Expression.  We have several cases where I would like to assert that a particular query is run against the database or arrange a query to return a specific result set.

    Thanks!
  7. Ricky
    Admin
    Ricky avatar
    467 posts

    Posted 17 Jan 2013 Link to this post

    Hi Josh,

    Thanks for bringing up the issue.

    The original bug that was mentioned in PITS is fixed now:

    http://www.telerik.com/support/pits.aspx#/public/justmock/5515

    Since the argument is a query expression itself, It will be redundant to wrap it around a Arg.Matcher as you can always do this:

    Mock.Arrange(() => repository.GetWhere(book => book.Id == 1)).Returns(expected).MustBeCalled();

    Hope this answers your question.

     

    Kind Regards
    Mehfuz
    the Telerik team
    Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
  8. Josh
    Josh avatar
    6 posts
    Member since:
    Apr 2012

    Posted 18 Jan 2013 Link to this post

    I saw that in the documentation, but I'm still missing something:

    Here is my test:
    <code>
                var charge = new Charge();
                var charges = new[] {charge};
                Mock.Arrange(() => repo.Get<Charge>(c => c.OrgID == 1 && c.IsActive, Arg.IsAny<List<string>>())).Returns(charges).Occurs(1);
    </code>

    And here is my code under test:
    <code>
                var list = genericRepository.Get<Charge>(c => c.OrgID == orgID && c.IsActive, new List<string> { "ChargeCode" });
    </code>

    My test fails when I assert my repo mock object saying it was called 0 times. Even if I change my code under test to use an explicit 1, the assertion fails.  I upgraded to the latest Nuget package for JustMock (lite).  Do you have any suggestions?

    Thank you, again.
  9. Ricky
    Admin
    Ricky avatar
    467 posts

    Posted 23 Jan 2013 Link to this post

    Hi Josh,

    Thanks a lot for the snippet.

    However, I would ask you to send us a sample project which will let us debug the issue further.

    Here are few things that you might like to watch out:

    • Since you are using lite version make sure that you are not mocking a non-virtual method.
    • Wrap the expression argument in a variable and then pass it both for arrange/actual execution and please check that it works.

    Kind Regards
    Mehfuz
    the Telerik team
    Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
  10. Josh
    Josh avatar
    6 posts
    Member since:
    Apr 2012

    Posted 30 Jan 2013 Link to this post

    Hi Mehfuz,

    Sorry for the delayed response.  I've whipped up a quick sample of my problem, but not sure how to get the ZIP to you. 
  11. Kaloyan
    Admin
    Kaloyan avatar
    872 posts

    Posted 30 Jan 2013 Link to this post

    Hi Josh,

    In order to send us the example, it will be best for you to open a new support ticket and to attach the .ZIP in your post.

    Feel free to ask for further assistance.

    Regards,
    Kaloyan
    the Telerik team
    Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
  12. Josh
    Josh avatar
    6 posts
    Member since:
    Apr 2012

    Posted 30 Jan 2013 Link to this post

    OK, I don't have an active Telerik subscription, so I'm going to post code here:

    Here is my class:

    public class Process
    {
        private IRepo repos;
     
        public Process(IRepo repo)
        {
            repos = repo;
        }
     
        public List<Payment> GetPayments(bool paid, int acctNo)
        {
            Expression<Func<Payment, bool>> func = p => p.IsPaid == paid && p.ToAccountId == acctNo;
            var result = repos.Get<Payment>(func);
            return result.ToList();
        }
    }

    And here is my test:
    public class ProcessTest
    {
        private IRepo mockRepo;
     
        [TestInitialize]
        public void Setup()
        {
            mockRepo = Mock.Create<IRepo>();
     
            var payment = new Payment() {IsPaid = false, ToAccountId = 1234};
            var list = new[] {payment};
     
            Expression<Func<Payment, bool>> func = p => p.IsPaid == false && p.ToAccountId == 1234;
            Mock.Arrange(() => mockRepo.Get<Payment>(func, null)).Returns(list).OccursOnce();
        }
     
        [TestMethod]
        public void TestMethod1()
        {
            var sut = new Process(mockRepo);
     
            var result = sut.GetPayments(false, 1234);
     
            Mock.Assert(mockRepo);
        }
    }

    This test fails and I don't know why.  

    Does the Expression have to be the exact same object?
    What if I want to use Arg.Matches() and just match on a part of the Expression?
  13. Ricky
    Admin
    Ricky avatar
    467 posts

    Posted 30 Jan 2013 Link to this post

    Hi Carlos,

    Thanks again for reaching out to us. 

    Your test looks fine, however it’s an issue with AndAlso type expression processing in JustMock. Good news is that we fixed the issue and should you need a fix urgently then please open a support where I will send you the build.

    On your second question, you don't need Arg.Matches since it’s a query parameter itself and using of Arg.Matches is redundant as your main goal here is to match a mocked method based on the expression you supplied in Mock.Arrange which you can write directly without the help of Arg.Matches


    Kind Regards
    Mehfuz
    the Telerik team
    Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
Back to Top
DevCraft R3 2016 release webinar banner