2010-05-01 29 views
27

Tôi đang Mocking giao diện kho lưu trữ của mình và không chắc chắn cách thiết lập một phương thức nhận biểu thức và trả về một đối tượng? Tôi đang sử dụng Moq và NUnitMoq.Mock <T> - cách thiết lập một phương thức có biểu thức

Interface:

public interface IReadOnlyRepository : IDisposable 
{ 
    IQueryable<T> All<T>() where T : class; 
    T Single<T>(Expression<Func<T, bool>> expression) where T : class; 
} 

Thử nghiệm với IQueryable đã thiết lập, nhưng không biết làm thế nào để thiết lập T Độc thân:

private Moq.Mock<IReadOnlyRepository> _mockRepos; 
private AdminController _controller; 
[SetUp] 
public void SetUp() 
{ 
    var allPages = new List<Page>(); 
    for (var i = 0; i < 10; i++) 
    { 
     allPages.Add(new Page { Id = i, Title = "Page Title " + i, Slug = "Page-Title-" + i, Content = "Page " + i + " on page content." }); 
    } 
    _mockRepos = new Moq.Mock<IReadOnlyRepository>(); 
    _mockRepos.Setup(x => x.All<Page>()).Returns(allPages.AsQueryable()); 
    //Not sure what to do here??? 
    _mockRepos.Setup(x => x.Single<Page>() 
    //---- 
    _controller = new AdminController(_mockRepos.Object); 
} 

Trả lời

37

Bạn có thể thiết lập nó như này:

_mockRepos.Setup(x => x.Single<Page>(It.IsAny<Expression<Func<Page, bool>>>()))//.Returns etc...; 

Tuy nhiên, bạn sẽ gặp phải một trong những thiếu sót của Moq. Bạn sẽ muốn đặt một biểu thức thực tế ở đó thay vì sử dụng It.IsAny, nhưng Moq không hỗ trợ thiết lập các phương thức có biểu thức với các biểu thức cụ thể (đó là một tính năng khó thực hiện). Khó khăn đến từ việc phải tìm ra liệu hai biểu thức là tương đương.

Vì vậy, trong thử nghiệm của bạn, bạn có thể vượt qua trong bất kỳExpression<Func<Page,bool>> và nó sẽ trả về bất kỳ thứ gì bạn đã thiết lập mô hình trả về. Giá trị của thử nghiệm là một chút pha loãng.

+1

Cảm ơn bạn đã trả lời. Tôi gặp lỗi với mã ở trên: Lỗi Đối số '1': không thể chuyển đổi từ 'nhóm phương thức' thành 'System.Linq.Expressions.Expression > – Paul

+0

@Paul: Xin lỗi, tôi đã bỏ '()'. Hãy thử với phiên bản mới nhất và nó sẽ hoạt động. –

+0

Cảm ơn bạn đã trả lời, đã làm việc, không lý tưởng như bạn đã đề cập, nhưng hoạt động! Cảm ơn một lần nữa. – Paul

6

Thực hiện cuộc gọi trả lại kết quả của biểu thức với biến allPages của bạn.

_mockRepos.Setup(x => x.Single<Page>(It.IsAny<Expression<Func<Page, bool>>>())) 
    .Returns((Expression<Func<Page, bool>> predicate) => allPages.Where(predicate)); 
1

Sử dụng Moq của It.IsAny<> mà không có một .CallBack buộc bạn phải viết code mà không được diễn tả bởi thử nghiệm của bạn. Thay vào đó, nó cho phép bất kỳ truy vấn/biểu thức nào đi qua, khiến cho giả của bạn về cơ bản vô dụng từ một góc nhìn thử nghiệm đơn vị.

Giải pháp: Bạn cần sử dụng Gọi lại để kiểm tra biểu thức HOẶC bạn cần hạn chế mô hình của mình tốt hơn. Dù bằng cách nào là lộn xộn và khó khăn. Tôi đã giải quyết vấn đề này miễn là tôi đã thực hành TDD. Cuối cùng tôi đã cùng nhau học một lớp trợ giúp để làm cho điều này trở nên biểu cảm hơn và ít lộn xộn hơn. Dưới đây là một ví dụ về một khả năng kết quả cuối cùng:

mockPeopleRepository 
    .Setup(x => x.Find(ThatHas.AnExpressionFor<Person>() 
    .ThatMatches(correctPerson) 
    .And().ThatDoesNotMatch(deletedPerson) 
    .Build())) 
    .Returns(_expectedListOfPeople); 

Dưới đây là các bài viết blog nói về nó và cung cấp cho các mã nguồn: http://awkwardcoder.com/2013/04/24/constraining-mocks-with-expression-arguments/

+0

Đóng góp rất hữu ích. – Paul

4

Tôi đã phát hiện ra rằng It.Is<T> nên được sử dụng ở vị trí của It.IsAny<T> để biết thêm kết quả chính xác.

Page expectedPage = new Page {Id = 12, Title = "Some Title"}; 
_mockRepos.Setup(x => x.Single<Page>(It.Is<Expression<Func<Page, bool>>>(u => u.Compile().Invoke(expectedPage)))) 
         .Returns(() => expectedPage); 
Các vấn đề liên quan