Christian Schnepf
Christian Schnepf

Reputation: 300

Unit Testing ServiceLayer with lambda and Moq

I am trying to test a lambda that is used on my repository by my service layer using Moq.

The Service:

public class CompanyService : TuneUpLog.ServiceLayer.ICompanyService
{
    private IRepository<Company> _repository;
    private IValidationDictionary _validatonDictionary;
    private Guid _userId;

    public CompanyService(Guid userId,IValidationDictionary validationDictionary, ObjectContext context)
        : this(userId, validationDictionary, new Repository<Company>(context))
    {
    }

    public CompanyService(Guid userId, IValidationDictionary validationDictionary, IRepository<Company> repository)
    {
        _validatonDictionary = validationDictionary;
        _repository = repository;

        if (userId == Guid.Empty)
            throw new SecurityException("UserId is required");
        else
            _userId = userId;
    }

    public IEnumerable<Company> ListCompany()
    {
        return _repository.Find(c => c.Users.Any(u => u.UserId == _userId));
    }
}

The Test:

[TestMethod]
    public void ListCompany_1Valid1Invalid_ReturnsValidCompany()
    {
        Mock<IRepository<Company>> fakeCompanyRepository = new Mock<IRepository<Company>>();

        CompanyService companyService = new CompanyService(USER_ID, new ModelStateWrapper(_modelState), fakeCompanyRepository.Object);

        //1 company for this user and 1 that isn't for this user
        List<Company> companies = new List<Company>()
            {
                new Company() { Id = 1, Name = "Test Company", AccountTypeId = 1, Users = { new User() { UserId = USER_ID } } },
                new Company() { Id = 2, Name = "2nd Test Company", AccountTypeId = 1, Users = { new User() { UserId = Guid.Empty } } }
            };

        fakeCompanyRepository.Setup(c => c.Find(It.IsAny<Expression<Func<Company, bool>>>())).Returns(companies.AsQueryable());

        //count should be 1
        Assert.AreEqual(1, companyService.ListCompany().Count());
    }

The Repository:

public interface IRepository<T> where T : class, IEntity
{
    void Add(T newEntity);
    void Edit(T entity);
    IQueryable<T> Find(Expression<Func<T, bool>> predicate);
    IQueryable<T> FindAll();
    T FindById(int id);
    void Remove(T entity);
    void Attach(T entity);
}

The Test is returning both companies instead of the 1st company that I expect. What am I doing wrong?

Upvotes: 1

Views: 1330

Answers (3)

Michael Brown
Michael Brown

Reputation: 9153

We use the same technique. You can capture the Expression being passed in when setting up the mock like so

fakeCompanyRepository.Setup(
  u => u.Find(It.IsAny<Expression<Func<Company, bool>>>()))
  .Returns(
     //Capture the It.IsAny parameter
     (Expression<Func<Company, bool>> expression) => 
     //Apply it to your queryable.
        companies.AsQueryable().Where(expression));

This will apply your expression to the companies collection.

Upvotes: 4

Rajeev Shenoy
Rajeev Shenoy

Reputation: 932

Your mock repository has been set up to return both the companies, which is why you get them both back.

You should be writing a unit test for the repository to check that the lambdas are executed correctly. In the service layer, the unit test only needs to verify that the repository has been called with the correct parameters.

Upvotes: 1

Bjorn Coltof
Bjorn Coltof

Reputation: 509

You're setting up your mock Find method to return a list of two objects, the userId check inside the lambda supplied is bypassed by this setup

Upvotes: 0

Related Questions