2016-11-21 49 views
0

我想知道除了構建一個用於模擬FormSql的包裝器以外,還有其他方法嗎?我知道這個方法是靜態的,但是因爲他們把AddEntityFrameworkInMemoryDatabase這樣的東西添加到了實體框架核心中,所以我認爲可能也有解決方案,我在我的項目中使用EF Core 1.0.1。在實體框架核心中嘲笑FromSql?

我的最終目標是測試這種方法:

public List<Models.ClosestLocation> Handle(ClosestLocationsQuery message) 
    { 
     return _context.ClosestLocations.FromSql(
      "EXEC GetClosestLocations {0}, {1}, {2}, {3}", 
      message.LocationQuery.Latitude, 
      message.LocationQuery.Longitude, 
      message.LocationQuery.MaxRecordsToReturn ?? 10, 
      message.LocationQuery.Distance ?? 10 
     ).ToList(); 
    } 

我想確保我的查詢與實體框架6基於this answer,我傳遞給它同一個對象,處理我能做些什麼像這樣:

[Fact] 
    public void HandleInvokesGetClosestLocationsWithCorrectData() 
    { 
     var message = new ClosestLocationsQuery 
     { 
      LocationQuery = 
       new LocationQuery {Distance = 1, Latitude = 1.165, Longitude = 1.546, MaxRecordsToReturn = 1} 
     }; 

     var dbSetMock = new Mock<DbSet<Models.ClosestLocation>>(); 

     dbSetMock.Setup(m => m.FromSql(It.IsAny<string>(), message)) 
      .Returns(It.IsAny<IQueryable<Models.ClosestLocation>>()); 

     var contextMock = new Mock<AllReadyContext>(); 

     contextMock.Setup(c => c.Set<Models.ClosestLocation>()).Returns(dbSetMock.Object); 

     var sut = new ClosestLocationsQueryHandler(contextMock.Object); 
     var results = sut.Handle(message); 

     contextMock.Verify(x => x.ClosestLocations.FromSql(It.IsAny<string>(), It.Is<ClosestLocationsQuery>(y => 
      y.LocationQuery.Distance == message.LocationQuery.Distance && 
      y.LocationQuery.Latitude == message.LocationQuery.Latitude && 
      y.LocationQuery.Longitude == message.LocationQuery.Longitude && 
      y.LocationQuery.MaxRecordsToReturn == message.LocationQuery.MaxRecordsToReturn))); 
    } 

但不像SqlQuery<T>在EF 6,FormSql<T>在EF核心是靜態擴展方法,我問這個問題,因爲我覺得我可能會從錯誤的角度來處理這個問題,或者有可能是一個比包裝更好的選擇,我會很欣賞這個想法。

+0

內部的EF核心[FromSql擴展方法](https://github.com/aspnet/EntityFramework/blob/1fa247b038927a7d7438f666dc11253f64e0432d/src/Microsoft.EntityFrameworkCore.Relational/RelationalQueryableExtensions.cs)正在爲'CreateQuery'上的呼叫'IQueriable.Provider'你可以看着嘲笑,達到你想要的。 – Nkosi

回答

1

如果您查看FromSql<T>中的代碼,您可以看到它打電話給source.Provider.CreateQuery<TEntity>。這是你必須嘲笑的。

在你的情況,我認爲你可以解決它與類似的東西:

var mockProvider = new Mock<IQueryProvider>(); 
mockProvider.Setup(s => s.CreateQuery(It.IsAny<MethodCallExpression>())) 
    .Returns(null as IQueryable); 
var mockDbSet = new Mock<DbSet<AllReady.Models.ClosestLocation>>(); 
mockDbSet.As<IQueryable<AllReady.Models.ClosestLocation>>() 
    .Setup(s => s.Provider) 
    .Returns(mockProvider.Object); 
var t = mockDbSet.Object; 
context.ClosestLocations = mockDbSet.Object; 

var sut = new ClosestLocationsQueryHandler(context); 
var results = sut.Handle(message); 

不知道你怎麼能VerifyMethodCallExpression之後,但我認爲這是可能的。或者,可能有辦法檢查生成的SQL。