我决定开始在我们的应用程序中编写单元测试。它使用实体框架和存储库模式。单元测试EF存储库模式与Moq
现在我想开始测试使用存储库的逻辑类。我在这里提供一个简单的例子。
public class GenericRepository : IRepository
{
public IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class
{
var entityName = GetEntityName<TEntity>();
return Context.CreateQuery<TEntity>(entityName);
}
private string GetEntityName<TEntity>() where TEntity : class
{
return typeof(TEntity).Name;
}
public IEnumerable<TEntity> Find<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class
{
return GetQuery<TEntity>().Where(predicate).AsEnumerable();
}
}
一个简单的逻辑类从日历表中降序排列返回不同年(是的,我知道这个词的日历在我们的代码拼写错误):
我在班上GenericRepository三种方法
public class GetDistinctYearsFromCalendar
{
private readonly IRepository _repository;
public GetDistinctYearsFromCalendar()
{
_repository = new GenericRepository();
}
internal GetDistinctYearsFromCalendar(IRepository repository)
{
_repository = repository;
}
public int[] Get()
{
return _repository.Find<Calender_Tbl>(c => c.Year.HasValue).Select(c => c.Year.Value).Distinct().OrderBy(c => c).Reverse().ToArray();
}
}
这是我的第一个测试:
[TestFixture]
public class GetDistinctYearsFromCalendarTest
{
[Test]
public void ReturnsDistinctDatesInCorrectOrder()
{
var repositoryMock = new Mock<IRepository>();
repositoryMock.Setup(r => r.Find<Calender_Tbl>(c => c.Year.HasValue)).Returns(new List<Calender_Tbl>
{
new Calender_Tbl
{
Date =
new DateTime(2010, 1, 1),
Year = 2010
},
new Calender_Tbl
{
Date =
new DateTime(2010, 2, 1),
Year = 2010
},
new Calender_Tbl
{
Date =
new DateTime(2011, 1, 1),
Year = 2011
}
}.AsQueryable());
var getDistinct = new GetDistinctYearsFromCalendar(repositoryMock.Object).Get();
Assert.AreEqual(2, getDistinct.Count(), "Returns more years than distinct.");
Assert.AreEqual(2011, getDistinct[0], "Incorrect order, latest years not first.");
Assert.AreEqual(2010, getDistinct[1], "Wrong year.");
}
}
这工作正常。但这实际上并不是我想要做的。由于我必须在模拟对象上设置方法Find,所以我还需要知道它是如何在我的逻辑类中调用的。如果我想做TDD,我不想介意这个。我想知道的是我的存储库应该提供哪些日历实体。我想设置GetQuery方法。 像这样:
repositoryMock.Setup(r => r.GetQuery<Calender_Tbl>()).Returns(new List<Calender_Tbl>
{
new Calender_Tbl
{
Date =
new DateTime(2010, 1, 1),
Year = 2010
},
new Calender_Tbl
{
Date =
new DateTime(2010, 2, 1),
Year = 2010
},
new Calender_Tbl
{
Date =
new DateTime(2011, 1, 1),
Year = 2011
}
}.AsQueryable());
所以,当发现是在GenericRepository类内部调用GetQuery应该得到正确的日历实体,我在安装GetQuery。但这当然不起作用。由于我没有设置我的模拟对象的查找方法,我没有得到任何实体。
那该怎么办?当然,我可以使用鼹鼠或其他一些模拟一切的框架,但我不想那样做。在课堂设计或测试中解决问题有什么我可以做的吗?
如果我不得不使用当前的解决方案,那么世界并不是世界末日,但如果财产年度变成不可空的整数?那么当然,我将不得不在逻辑类中更改我的实现,但我也必须更改测试。我想尽量避免这种情况。
我认为这样做是有“GetDistinctYearsFromCalendar”依赖于“IRepository”的一种方式。你可以模拟出“GenericRepository”的测试这样“GetDistinctYearsFromCalendar”隔离。有关更多详细信息,请参阅http://en.wikipedia.org/wiki/Dependency_injection。 – Michael
好吧,我没有看到内部ctor。你在同一个项目中有测试和生产代码吗?我认为正确的做法是完成依赖注入并跳过默认的ctor。 – Michael
我知道我可以只写我的逻辑为: 返回_repository.GetQuery(),其中(C => c.Year.HasValue)。选择(C => c.Year.Value).Distinct()。 OrderBy(c => c).Reverse()。ToArray(); 没有我一直测试到另一个项目,但暴露的内部用汇编指令的测试项目。 但是,如果我从来不使用另一种类型比GenericRepository呢?那么是否需要一直进行依赖注入? 这似乎是最好的解决方案吗?我是盲目的,想要使用存储库的所有功能。 –
John