Tôi quyết định bắt đầu viết các bài kiểm tra đơn vị trong ứng dụng của chúng tôi. Nó sử dụng Entity Framework với một mẫu kho lưu trữ.Kiểm tra đơn vị Mẫu kho lưu trữ EF với Moq
Bây giờ tôi muốn bắt đầu thử nghiệm các lớp logic đang sử dụng các kho lưu trữ. Tôi cung cấp một ví dụ đơn giản ở đây.
Ba trong số các phương pháp của tôi trong GenericRepository lớp:
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();
}
}
Một lớp logic đơn giản trở về năm khác biệt với một bảng lịch trong thứ tự giảm dần (có tôi biết từ lịch được sai chính tả trong mã của chúng tôi):
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();
}
}
Và đây là thử nghiệm đầu tiên của tôi:
[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.");
}
}
này đang làm việc tốt. Nhưng đây không phải là những gì tôi muốn làm. Vì tôi phải thiết lập phương thức Find trên đối tượng giả, tôi cũng cần phải biết nó sẽ được gọi như thế nào trong lớp logic của tôi. Nếu tôi muốn làm TDD, tôi không muốn bận tâm về điều này. Tất cả những gì tôi muốn biết là các thực thể Lịch mà kho lưu trữ của tôi sẽ cung cấp. Tôi muốn thiết lập phương thức GetQuery. Như thế này:
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());
Vì vậy, khi Find đang kêu gọi GetQuery nội bộ trong lớp GenericRepository nó sẽ nhận được các đơn vị Lịch đúng mà tôi thiết lập trong GetQuery. Nhưng điều này không làm việc tất nhiên. Vì tôi chưa thiết lập phương thức Find của đối tượng giả của mình nên tôi không nhận được bất kỳ thực thể nào.
Vậy phải làm gì? Tất nhiên tôi có lẽ có thể sử dụng nốt ruồi hoặc một số khuôn khổ khác mà mocks tất cả mọi thứ nhưng tôi không muốn làm điều đó. Có điều gì tôi có thể làm trong thiết kế của lớp học hoặc bài kiểm tra để giải quyết vấn đề này không?
Nó không phải là kết thúc của thế giới nếu tôi phải đi với giải pháp hiện tại của tôi nhưng nếu năm tài sản biến thành một int không nullable? Sau đó, tất nhiên tôi sẽ phải thay đổi thực hiện của tôi trong lớp logic nhưng tôi cũng sẽ phải thay đổi thử nghiệm. Tôi muốn tránh điều này.
Tôi nghĩ một cách để thực hiện việc này là 'GetDistinctYearsFromCalendar' phụ thuộc vào 'IRepository'. Bằng cách đó bạn có thể giả lập 'GenericRepository' một bài kiểm tra 'GetDistinctYearsFromCalendar' bị cô lập. Xem http://en.wikipedia.org/wiki/Dependency_injection để biết thêm chi tiết. – Michael
Được rồi, tôi không thấy ctor nội bộ. Bạn có thử nghiệm và mã sản xuất trong cùng một dự án không? Tôi nghĩ rằng đúng cách để làm điều này là làm tiêm phụ thuộc tất cả các cách thức thông qua và bỏ qua các ctor mặc định. – Michael
Tôi nhận ra rằng tôi chỉ có thể viết logic của mình là: return _repository.GetQuery(). Where (c => c.Year.HasValue) .Select (c => c.Year.Value) .Distinct(). OrderBy (c => c) .Reverse(). ToArray(); Không, tôi giữ các bài kiểm tra trong một dự án khác nhưng phơi bày nội bộ cho dự án thử nghiệm với các chỉ thị lắp ráp. Nhưng nếu tôi không bao giờ sử dụng loại nào khác so với GenericRepository thì sao? Có cần thiết phải tiêm phụ thuộc vào tất cả các cách sau đó không? Điều đó có vẻ là giải pháp tốt nhất phải không? Tôi đã bị mù và muốn sử dụng tất cả các chức năng của kho lưu trữ. –
John