简体   繁体   中英

Using Moq for a repository interface method?

I have the following method on my repository interface:

IQueryable<T> GetQuery<T>(Expression<Func<T, bool>> predicate) where T : class;

I have a class I'm going to act on in a unit test with the following constructor:

public MyClass(IUnitOfWork unitOfWork)

On IUnitOfWork Interface there is an exposed Repository property:

Repository Repository { get; }

So I'm trying to unit test the MyClass.DoSomething() method like so:

[TestInitialize]
public void Setup()
{

    accounts = new List<Account>()
    {
        new Account()
            {
               Id = 123
            }
    };
}

Next I have the unit test Arrange section which is failing:

//Arrange
var repositoryMock = new Mock<IUnitOfWork>();
repositoryMock.Setup(x => x.Repository.GetQuery<Account>(y => y.Id == 123))
                           .Returns(accounts.AsQueryable()); //This setup always fails
var myClass = new MyClass(repositoryMock.Object); //don't even get here

The exception I get is:

System.NotSupportedException: Invalid setup on a non-virtual (overridable in VB) member: x => x.Repository.GetQuery(y => y.Id == 123)

I've tried other variations of the Setup on the mock:

repositoryMock.Setup(x => x.Repository.GetQuery<Account>()).Returns((Account a) => accounts.AsQueryable().Where(z => z.Id == 123));

and

repositoryMock.Setup(x => x.Repository.GetQuery<Account>(y => y.Id == 123)).Returns((Account a) => accounts.AsQueryable().Where(z => z == a));

But to no success; I get the identical exception each time. They always throw the same exception when I run the unit test. Since I am using an Interface to be mocked, why am I getting this exception and how do I do this properly? Thanks!

Instead of your current setup try this:

//Arrange
var repositoryMock = new Mock<IUnitOfWork>();
repositoryMock.Setup(x => x.Repository.GetQuery<Account>(
        It.IsAny<Expression<Func<T, bool>>>());
    .Returns(accounts.AsQueryable()); // This should not fail any more
var myClass = new MyClass(repositoryMock.Object); 

In reality, you do not need to pass any concrete lambda because you are returning your list either way.

The Repository property you have shown is not of an interface type. It's some concrete class. And as the error message tells you, you cannot define expectations on non virtual methods. So what you should do instead is to work with an abstraction if you want to be able to mock it:

IRepository Repository { get; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM