C#+模拟服务层?

时间:2010-10-17 11:06:55

标签: c# unit-testing mocking moq

我刚刚开始使用Moq进行单元测试/模拟,并遇到了问题..

我有一个名为“CustomerService”的服务层,其中包含以下代码:

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;
    }
}

我的存储库类是通用的,并且遵循:

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;
                }
            }
        }
    }

现在是我的问题..如何进行单元测试以检查我的GetCustomerById是否返回null?

已经尝试过:

[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);
}

没有运气......

3 个答案:

答案 0 :(得分:5)

您需要将Repository<T>.Get方法设为虚拟,以便Moq可以覆盖它并返回您设置的值:

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

并在测试中,更改

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

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

表示为传入的任何Customer返回新的Expression<Func<Customer, bool>>。理想情况下,您会测试一个特定的表达式,但根据此SO question的接受答案,Moq无法执行此操作。< / p>

如果您想测试您的服务层没有对存储库返回的Customer执行任何意外操作,而不是测试是否返回任何 Customer ,您可以设置模拟Customer(确保将CustomerId属性设为虚拟)并声明服务层返回的Customer具有预期的属性。

[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

答案 1 :(得分:0)

你必须针对界面创建模拟。

然后,您需要将类中的成员设置为mock而不是实现者

然后你需要在你为方法创建的模拟上调用.Setup。记住使用方法链来使它可以验证。

在测试中运行该方法,然后调用mock.Verify()

如果您需要,明天会添加代码。我可以使用大量的代码示例。

答案 2 :(得分:0)

你不能这样做的原因是因为一个lambda x => x.CustomerId == id不等于另一个lambda x => x.CustomerId == id所以Moq不能匹配它们。

但是,如果你有一个关于你的共同操作的课程:

public class CustomerQueries {
    public static Predicate<Customer> ById(int id) = x => x.CustomerId == id;
}

并在代码和测试中重用这个lambda,然后你的Moq应该没有任何问题。您也可以在类的已知实例上使用方法,只要它是完全相同的委托,而不仅仅是类似的一个或另一个副本。

PS:您是否考虑过使用Predicate<T>代替Expression<Func<T, bool>>?它更容易阅读和理解目的。

相关问题