2014-11-20 24 views
14

Làm cách nào để thử phương pháp AsNoTracking?
Trong ví dụ dưới đây, DbContext đã tiêm vào lớp dịch vụ.Nó hoạt động tốt nếu tôi xóa phương thức mở rộng AsNoTracking khỏi phương thức GetOrderedProducts, nhưng với kiểm tra AsNoTracking không thành công vì nó trả về null. Tôi cũng đã thử giả lập AsNoTracking để trả lại giá trị thích hợp nhưng nó không hoạt động.Mock AsNoTracking Entity Framework

lợi nhuận
public interface IUnitOfWork 
{ 
    IDbSet<TEntity> Set<TEntity>() where TEntity : class; 
    int SaveAllChanges(); 
} 

public class Entites : DbContext, IUnitOfWork 
{ 
    public virtual DbSet<Product> Products { get; set; } // This is virtual because Moq needs to override the behaviour 

    public new virtual IDbSet<TEntity> Set<TEntity>() where TEntity : class // This is virtual because Moq needs to override the behaviour 
    { 
     return base.Set<TEntity>(); 
    } 

    public int SaveAllChanges() 
    { 
     return base.SaveChanges(); 
    } 
} 

    public class ProductService 
{ 
    private readonly IDbSet<Product> _products; 
    private readonly IUnitOfWork _uow; 

    public ProductService(IUnitOfWork uow) 
    { 
     _uow = uow; 
     _products = _uow.Set<Product>(); 
    } 
    public IEnumerable<Product> GetOrderedProducts() 
    { 
     return _products.AsNoTracking().OrderBy(x => x.Name).ToList(); 
    } 
} 

    [TestFixture] 
public class ProductServiceTest 
{ 
    private readonly ProductService _productService; 

    public ProductServiceTest() 
    { 
     IQueryable<Product> data = GetRoadNetworks().AsQueryable(); 
     var mockSet = new Mock<DbSet<Product>>(); 
     mockSet.As<IQueryable<Product>>().Setup(m => m.Provider).Returns(data.Provider); 
     mockSet.As<IQueryable<Product>>().Setup(m => m.Expression).Returns(data.Expression); 
     mockSet.As<IQueryable<Product>>().Setup(m => m.ElementType).Returns(data.ElementType); 
     mockSet.As<IQueryable<Product>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator()); 
     var context = new Mock<Entites>(); 
     context.Setup(c => c.Products).Returns(mockSet.Object); 
     context.Setup(m => m.Set<Product>()).Returns(mockSet.Object); 
     context.Setup(c => c.Products.AsNoTracking()).Returns(mockSet.Object); 
     _productService = new ProductService(context.Object); 
    } 

    private IEnumerable<Product> GetRoadNetworks() 
    { 
     return new List<Product> 
     { 
      new Product 
      { 
       Id = 1, 
       Name = "A" 
      }, 
      new Product 
      { 
       Id = 2, 
       Name = "B" 
      }, 
      new Product 
      { 
       Id = 1, 
       Name = "C" 
      } 
     }; 
    } 

    [Test] 
    public void GetOrderedProductTest() 
    { 
     IEnumerable<Product> products = _productService.GetOrderedProducts(); 
     List<string> names = products.Select(x => x.Name).ToList(); 
     var expected = new List<string> {"A", "B", "C"}; 
     CollectionAssert.AreEqual(names, expected); 
    } 
} 

Vấn đề là AsNoTracking null trong bài kiểm tra đơn vị enter image description here

+0

Các bài phát biểu đề nghị một cái gì đó khác hơn là rỗng nên được trả lại: http://msdn.microsoft.com/en-us/library/gg679352%28v= vs.103% 29.aspx –

+0

@ ta.speot.is Đúng vậy, nhưng nó trả về null. – Shahin

Trả lời

36

Nhìn vào source code của phương pháp AsNoTracking() phần mở rộng:

public static IQueryable AsNoTracking(this IQueryable source) 
{ 
    var asDbQuery = source as DbQuery; 
    return asDbQuery != null ? asDbQuery.AsNoTracking() : CommonAsNoTracking(source); 
} 

Kể từ source (bạn DbSet<Product> bạn đang cố gắng để thử) thực sự là một DbQuery (vì DbSet được bắt nguồn từ DbQuery), nó sẽ cố gắng để gọi phương thức AsNoTracking() 'thực sự' không được chế giễu, trả về giá trị rỗng một cách hợp lý.

Cố gắng thử phương pháp AsNoTracking() cũng như:

mockSet.Setup(x => x.AsNoTracking()).Returns(mockSet.Object); 
+0

Tính năng này không hoạt động trên lõi dotnet/EF: Tham chiếu biểu thức một phương thức không thuộc đối tượng được giả định: x => x.AsNoTracking (). Tôi đoán vì AsNoTracking() không có trên IQueryable nữa mà thay vào đó là 'Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions'? Bất kỳ ý tưởng về một giải pháp? – Bassebus

+0

@Bassebus, tôi không đủ quen thuộc với lõi EF để trả lời câu hỏi nhưng nó có thể xứng đáng với một câu hỏi mới – haim770

+0

được, cảm ơn. Tôi đã làm một số googling hơn và nghĩ rằng đây có thể là vấn đề/giải pháp https://github.com/aspnet/EntityFramework/issues/7937 – Bassebus

3

Bạn có:

context.Setup(c => c.Products).Returns(mockSet.Object); 
context.Setup(m => m.Set<Product>()).Returns(mockSet.Object); 
context.Setup(c => c.Products.AsNoTracking()).Returns(mockSet.Object); 

Nhưng hãy nhớ rằng phương pháp khuyến nông chỉ là cú pháp đường. Vì vậy:

c.Products.AsNoTracking() 

là thực sự chỉ:

System.Data.Entity.DbExtensions.AsNoTracking(c.Products) 

do đó thiết lập mô hình của bạn ở trên là vô nghĩa.

Câu hỏi đặt ra là tĩnh DbExtensions.AsNoTracking(source) method thực sự làm đối số của nó. Ngoài ra, hãy xem the thread What difference does .AsNoTracking() make?

Điều gì sẽ xảy ra nếu bạn chỉ xóa Setup liên quan đến AsNoTracking từ lớp thử nghiệm của mình?

Có thể hữu ích khi cung cấp cho tất cả mocks MockBehavior.Strict của bạn. Trong trường hợp đó, bạn sẽ khám phá ra nếu các thành viên phương thức tĩnh gọi trên chúng, được giả lập bởi Moq (tức là các phương thức/thuộc tính ảo theo nghĩa chung). Có thể bạn có thể giả lập method DbQuery.AsNoTracking không tĩnh nếu cần.

+0

Cảm ơn bạn, tôi cần sử dụng AsNoTracking để cải thiện hiệu suất truy vấn. Tôi đang tìm cách khắc phục sự cố ngoại lệ không có giá trị này khi tôi sử dụng AsNoTracking trong các lớp dịch vụ. – Shahin

+0

Trong EF của tôi (phiên bản 6.0), nó không phải lúc nào cũng là một phương thức mở rộng mà là một phương thức ảo được định nghĩa trong 'DbQuery <>'. Chỉ khi bạn đề cập đến dữ liệu của mình là 'IQueryable <>' thì bạn sẽ phải sử dụng phương thức mở rộng. – haim770

+1

@ haim770 Bạn hoàn toàn đúng. Câu trả lời của bạn chính xác hơn nhiều so với tôi, mặc dù tôi đã gợi ý về phương thức không tĩnh trên 'DbQuery <>' trong câu cuối cùng. Tôi sẽ lặp lại rằng nếu anh ta đã sử dụng mocks 'Strict', anh ta sẽ có một ngoại lệ nói cho anh ta phương pháp anh ta cần để chế nhạo, thay vì chỉ đợi cho đến khi' NullReferenceException' xuất hiện. Mọi người sử dụng mocks lỏng lẻo quá nhiều. –