Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# + Mock service layer?

I have just started playing with unit testing / mocks using Moq, and ran into a problem..

I have a Service layer named "CustomerService" which have following code:

public interface ICustomerService
{
    Customer GetCustomerById(int id);
}

public class CustomerService : ICustomerService
{
    private IRepository<Customer> customerRepository;

    public CustomerService(IRepository<Customer> rep)
    {
        customerRepository = rep;
    }
    public Customer GetCustomerById(int id)
    {
        var customer = customerRepository.Get(x => x.CustomerId == id);

        if (customer == null)
            return null;

        return customer;
    }
}

My repository class is generic, and are following:

public interface IRepository<T> : IDisposable where T : class
    {
        T Get(Expression<Func<T, bool>> predicate);
    }

    public class Repository<T> : IRepository<T> where T : class
    {
        private ObjectContext context;
        private IObjectSet<T> objectSet;

        public Repository()
            : this(new demonEntities())
        {
        }

        public Repository(ObjectContext ctx)
        {
            context = ctx;
            objectSet = context.CreateObjectSet<T>();
        }

        public T Get(Expression<Func<T, bool>> predicate)
        {
            T entity = objectSet.Where<T>(predicate).FirstOrDefault();

            if (entity == null)
                return null;

            return objectSet.Where<T>(predicate).FirstOrDefault();
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (context != null)
                {
                    context.Dispose();
                    context = null;
                }
            }
        }
    }

Now is my question.. How can I make unit test to check whether my GetCustomerById returns null or not?

Already tried:

[TestMethod]
public void GetCustomerTest()
{
    const int customerId = 5;

    var mock = new Mock<IRepository<Customer>>();
    mock.Setup(x => x.Get(z => z.CustomerId == customerId))
        .Returns(new Customer());

    var repository = mock.Object;
    var service = new CustomerService(repository);
    var result = service.GetCustomerById(customerId);

    Assert.IsNotNull(result);
}

without luck...

like image 537
ebb Avatar asked Oct 17 '10 11:10

ebb


1 Answers

You need to make the Repository<T>.Get method virtual so Moq can override it and return the value you set up:

public virtual T Get(Expression<Func<T, bool>> predicate)

and in your test, change

mock.Setup(x => x.Get(z => z.CustomerId == customerId))
        .Returns(new Customer());

to

mock.Setup(x => x.Get(It.IsAny<Expression<Func<Customer, bool>>>()))
        .Returns(new Customer());

which says return a new Customer for any Expression<Func<Customer, bool>> passed in. Ideally you would test a specific expression, but per the accepted answer to this SO question, Moq cannot do this.

If you wanted to test that your service layer was not doing anything unexpected to the Customer returned by the repository, instead of testing to see that any Customer was returned, you could set up a mock Customer (being sure to make the CustomerId property virtual) and assert that the Customer returned by the service layer had the expected properties.

[TestMethod]
public void GetCustomerTest()
{
    const int customerId = 5;

    var mockCustomer = new Mock<Customer>();

    mockCustomer.SetupGet(x => x.CustomerId)
        .Returns(customerId);

    var mock = new Mock<IRepository<Customer>>();

    mock.Setup(x => x.Get(It.IsAny<Expression<Func<Customer, bool>>>()))
        .Returns(mockCustomer.Object);

    var repository = mock.Object;
    var service = new CustomerService(repository);
    var result = service.GetCustomerById(customerId);

    Assert.AreEqual(customerId, result.CustomerId);
}

HTH

like image 169
Jeff Ogata Avatar answered Sep 19 '22 10:09

Jeff Ogata