2014-11-20 1 views
14

어떻게 AsNoTracking 메서드를 조롱합니까?
아래 예제에서 DbContext는 서비스 클래스에 삽입되었습니다. GetOrderedProducts 메서드에서 AsNoTracking 확장 메서드를 제거하면 제대로 작동하지만 null을 반환하기 때문에 AsNoTracking 테스트가 실패합니다. 나는 또한 적절한 값을 반환하기 위해 AsNoTracking을 모의하려고했지만 작동하지 않았습니다.모의 AsNoTracking 엔티티 프레임 워크

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); 
    } 
} 

문제는 AsNoTracking되어 반환 단위 테스트에 널 (null) enter image description here

+0

발언이 null이 아닌 다른 무언가를 제안 반환해야합니다 http://msdn.microsoft.com/en-us/library/gg679352%28v= vs.103 % 29.aspx –

+0

@ ta.speot.is 맞습니다. 그러나 null을 반환합니다. – Shahin

답변

36

AsNoTracking() 확장 메서드의 source code에서 상대 :

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

source 때문에 (당신의 DbSet<Product> 당신이 조롱하려는)는 DbQuery (DbSetDbQuery에서 파생되기 때문에),이 호출을 시도 참 정당한 null을 반환하는 '실제'(비 모의 된) AsNoTracking() 메소드.

시도뿐만 아니라 AsNoTracking() 방법을 조롱 :

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

이것은 dotnet/EF core에서 작동하지 않습니다 : Expression은 조롱 된 객체에 속하지 않는 메소드를 참조합니다 : x => x.AsNoTracking (). AsNoTracking()이 IQueryable에 더 이상 없기 때문에 대신 'Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions'에있는 것 같습니까? 솔루션에 대한 아이디어가 있습니까? – Bassebus

+0

@Bassebus, 질문에 대답하기 위해 EF 코어에 익숙하지는 않지만 새로운 질문을 할만한 자격이 있습니다. – haim770

+0

감사합니다. 좀 더 인터넷 검색을하고 이것이 문제/해결책 일 수 있다고 생각합니다 https://github.com/aspnet/EntityFramework/issues/7937 – Bassebus

3

당신은이 :

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); 

을하지만 그 확장 방법은 단지 문법 설탕을 기억. 그래서 :

c.Products.AsNoTracking() 

정말 그냥 :

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

그러므로 위의 모형 설정이 의미가 없습니다.

질문은 정적 인 DbExtensions.AsNoTracking(source) method이 실제로 논쟁하는 것입니다. 더보기 the thread What difference does .AsNoTracking() make?

Setup을 시험 수업에서 AsNoTracking 번으로 삭제하면 어떻게됩니까?

귀하의 모든 목을 MockBehavior.Strict에게주는 것이 도움이 될 수 있습니다. 이 경우 정적 메소드가 호출하는 멤버가 Moq (즉, 일반적인 의미에서 가상 메소드/속성)에 의해 모조가 될 수 있는지 확인할 수 있습니다. 필요할 경우 비 정적 인 method DbQuery.AsNoTracking을 조롱 할 수 있습니다.

+0

감사합니다. 쿼리 성능을 향상시키기 위해 AsNoTracking을 사용해야합니다. 서비스 클래스에서 AsNoTracking을 사용할 때이 null 예외 문제를 해결할 수있는 방법을 찾고 있습니다. – Shahin

+0

내 EF (버전 6.0)에서는 항상 확장 메서드가 아니며'DbQuery <> '에 정의 된 가상 메서드입니다. 데이터를'IQueryable <> '로 참조 할 때만 확장 메서드를 사용해야합니다. – haim770

+1

@ haim770 당신은 절대적으로 맞습니다. 마지막 문장에서'DbQuery <> '에 대한 비 정적 메소드에 대한 힌트를했지만 답변은 제 것보다 훨씬 정확합니다. 나는 그가'Strict' mock을 사용했다면, 그가'NullReferenceException'이 발생할 때까지 기다리지 않고 모의해야 할 메소드를 알려주는 예외를 가지고 있다고 반복합니다. 사람들은 헐렁한 목을 너무 많이 사용합니다. –