3

I have a query that goes

var myRecord = myRepository.All().Any(e => e.Id == id);

I mocked it with this

this._myMockRepository
    .Setup(s => s.All().Any(It.IsAny<Expression<Func<MyObject, bool>>>()))
    .Returns(this.GetFakeMyObjects().Any(t => t.Id == 1));

How do I mock the .All().Any(...) call? The exception I get is a NotSupportedException with message :

Expression references a method that does not belong to the mocked object: s => s.All().Any < MyRepositoryObject > (It.IsAny < Expression`1 > ())

I tried breaking it up like so

this._myMockRepository
    .Setup(s => s.All(It.IsAny<Expression<Func<MyObject, bool>>>()))
    .Returns(this.GetFakeMyObjects());
this._myMockRepository
    .Setup(s => s.All().Any(It.IsAny<Expression<Func<MyObject, bool>>>()))
    .Returns(this.GetFakeMyObjects().Any(t => t.Id == 1));

Fairly new to Moq so any tips would be appreciated.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
Neil Humby
  • 253
  • 4
  • 15

2 Answers2

1

Update

If All() is not an extension method then update the mock setup to return a queriable when called.

this._myMockRepository
    .Setup(_ => _.All())
    .Returns(this.GetFakeMyObjects());//<-- assuming GetFakeMyObjects returns an enumerable

This assumes a repository defined something like

public interface IRepository {
    IEnumerable<MyObject> All();
}

or close to that definition.


Original Answer

Those are all extension methods. Moq does not mock extension methods.

What you need to mock is what it returned when the mocked members are called that can satisfy the provided linq queries.

The assumption based on the code snippet suggests that the subject of the mock is enumerable.

The following extension method can be used to mock the behavior needed to perform queries on an enumerable mock.

/// <summary>
/// Converts a generic <seealso cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/>  to a <see cref="Moq.Mock"/> implementation of queryable list 
/// </summary>
public static Mock<T> SetupQueryable<T, TItem>(this Mock<T> queryableMock, IEnumerable<TItem> source)
    where T : class, IEnumerable<TItem> {

    var queryableList = source.AsQueryable();

    queryableMock.As<IQueryable<TItem>>().Setup(x => x.Provider).Returns(queryableList.Provider);
    queryableMock.As<IQueryable<TItem>>().Setup(x => x.Expression).Returns(queryableList.Expression);
    queryableMock.As<IQueryable<TItem>>().Setup(x => x.ElementType).Returns(queryableList.ElementType);
    queryableMock.As<IQueryable<TItem>>().Setup(x => x.GetEnumerator()).Returns(() => queryableList.GetEnumerator());

    return queryableMock;
}

and can be used like this.

var fakeItems = GetFakeMyObjects();
var _myMockRepository = new Mock<IMyRepository>()
_myMockRepository.SetupQueryable(fakeItems);

This would now allow queries to be called on the mocked object when testing.

var myRepository = _myMockRepository.Object;
var myRecord = myRepository.All().Any(e => e.Id == id);
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Bayete @Nkosi ;) I've almost got this working, unfortunately my T cannot be converted to IEnumerable. Could you share your implementation of GetFakeMyObjects()? – Neil Humby May 16 '17 at 09:22
  • @NeilHumby show the definition of the repository being mocked. I had assumed that it was enumerable and that `All` was a linq extension method. Provide the requested information so that the answer can be updated correctly. – Nkosi May 16 '17 at 09:55
0

You can't mock static methods, which is what Any is. It's hard to tell from you code sample, but if All() is not an extension method, just mock it and then test that whatever method you're calling returns the expected result of Any. If it's static as well, then it's likely invoking GetEnumerator under the covers and you can instead mock that.

If you need more guidance than that, you'll need to post a bit of the method you're trying to test (i.e. the one that is consuming the repository).

Community
  • 1
  • 1
Patrick Quirk
  • 23,334
  • 2
  • 57
  • 88