1

I am writing some unit tests. One of the tests I have written has unexpected behavior and I am confused about what has happened exactly. The problem is in mocking GetAsync method. When I use a variable like limit, the code does not work correctly, but if I use const instead of variables it works fine. Here is my source code:

namespace TestClass
{
    public class LambdaTest<T> where T : TestModel
    {
        readonly List<T> _list = new List<T>();
        public virtual IEnumerable<T> GetAsync(Expression<Func<T, bool>> predicate)
        {
            return _list.AsQueryable().Where(predicate).Where(x => !x.IsDeleted).ToList();
        }

        public IEnumerable<T> TestMethod()
        {
            int limit = 100;
            var result = GetAsync(p => !p.IsDeleted && (DateTime.Now - p.CreationDate).TotalHours < limit);
            return result;
        }
    }

    public class TestModel
    {
        public long Id { get; set; }
        public bool IsDeleted { get; set; }
        public DateTime CreationDate { get; set; }
    }
}

And the Test project:

namespace TestClass.Tests
{
    public class ExpressionTest
    {
        [Fact]
        public void SimpleTest()
        {
            var returnValue = new List<TestModel>
            {
                new TestModel() {CreationDate = DateTime.Now, Id = 1},
                new TestModel() {CreationDate = DateTime.Now, Id = 2}
            };
            var sut = new Mock<LambdaTest<TestModel>>();
            int limit = 100;
            sut.Setup(x => x.GetAsync(p => !p.IsDeleted && (DateTime.Now - p.CreationDate).TotalHours < limit))
               .Returns(returnValue);

            var result = sut.Object.TestMethod();

            Assert.True(true);
        }
    }
}

I can not use const here. I know about expression tree and some other subjects related to this problem, but can anyone explain what is happening exactly here and how can I solve this problem?

I will appreciate any help.

10
  • 1
    Moq can't match the expressions which is why the result is false Commented Mar 4, 2019 at 21:15
  • thanks, @Nkosi , so is there any way to change the expression to solve this problem? (if I use const digits it works fine) , and if not, is there any way to write a good test method? Commented Mar 4, 2019 at 21:30
  • How _list get populated in TestClass? Commented Mar 5, 2019 at 1:03
  • @Fabio , it doesn't matter, you can consider it something like: var returnValue = new List<TestModel> { new TestModel() {CreationDate = DateTime.Now, Id = 1}, new TestModel() {CreationDate = DateTime.Now, Id = 2} }; Commented Mar 5, 2019 at 4:54
  • 1
    @Pedram, this is a different interpretation of unit tests - common one. Which will introduce problems you has. Another interpretation is where unit - is unit of behaviour. Where you will mock only dependencies which makes your tests slow(external resource) or very very complicated to setup, there you can introduce mocks. In your case you already has data in memory which you can preconfigure for tests, then you need only define expected result and run test with all dependencies included. Commented Mar 5, 2019 at 8:18

1 Answer 1

1

Finally, I solved the problem. I simulated the method behavior by something like this:

sut.Setup(x => x.GetAsync(
                It.IsAny<Expression<Func<TestModel, bool>>>()
            ))
            .Returns((Expression<Func<TestModel, bool>> predict) =>
            {
                var result = _list.Where(predict.Compile());
                return Task.FromResult(result);
            });
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.