C#+模拟服务层?
我刚开始用的单元测试播放嘲笑使用/起订量,并遇到了一个问题..C#+模拟服务层?
我已经下面的代码名为“为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返回空或不是?
已经尝试过:
[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);
}
没有运气...
你需要让Repository<T>.Get
方法虚拟的,这样起订量可以覆盖它并返回您设置的值:
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>>
pas最好你会测试一个特定的表达式,但根据这个SO question的接受答案,Moq不能做到这一点。
如果你想测试你的服务层,未进行任何意外由库返回的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
你必须创建对接口的模拟。
然后需要在类中设置成员的模拟,而不是实现者
然后需要调用.Setup你的方法创建的模拟.. rememver使用方法链,使其验证。
在您的测试运行的方法,然后调用mock.Verify()如果你需要
将添加代码的明天。我在工作中可以使用大量代码示例。
嗯..这几乎已经是我所做的atm(如果你看我的帖子,我已经更新了一些更多的代码) ... – ebb 2010-10-17 11:18:48
从你的更新和其他意见,我无法帮助。对解决方案感兴趣虽然我放弃了当我尝试类似的东西。 – 2010-10-17 21:45:34
你不能这样做,这是因为一个拉姆达x => x.CustomerId == id
不等于另一个lambda x => x.CustomerId == id
所以起订量不能满足他们的原因。
但是,如果你有,比如说,在与您共同操作的类:
public class CustomerQueries {
public static Predicate<Customer> ById(int id) = x => x.CustomerId == id;
}
和再利用这个拉姆达在代码和测试,那么你的起订量应该通过没有任何问题。您也可以在类的已知实例上使用方法,只要它是完全相同的代理,而不仅仅是类似的副本。
PS:你有没有考虑过使用Predicate<T>
而不是Expression<Func<T, bool>>
?阅读和理解目的更容易。
通过传递模拟库。使用不在模拟存储库中的ID进行调用。顺便说一句,这是没有太多的测试.... – 2010-10-17 11:09:42
已经尝试过,没有运气... – ebb 2010-10-17 11:12:13