2017-06-02 102 views
2

我試圖爲IServiceProvider創建一個模擬(使用MOQ),這樣我可以測試我的倉儲類:起訂量的IServiceProvider/IServiceScope

public class ApiResourceRepository : IApiResourceRepository 
{ 
    private readonly IServiceProvider _serviceProvider; 

    public ApiResourceRepository(IServiceProvider serviceProvider) 
    { 
     _serviceProvider = serviceProvider; 
     _dbSettings = dbSettings; 
    } 

    public async Task<ApiResource> Get(int id) 
    { 
     ApiResource result; 

     using (var serviceScope = _serviceProvider. 
      GetRequiredService<IServiceScopeFactory>().CreateScope()) 
     { 
      var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>(); 
      result = await 
       context.ApiResources 
       .Include(x => x.Scopes) 
       .Include(x => x.UserClaims) 
       .FirstOrDefaultAsync(x => x.Id == id); 
     } 

     return result; 
    } 
} 

我在創建模擬對象的嘗試如下:

Mock<IServiceProvider> serviceProvider = new Mock<IServiceProvider>(); 

serviceProvider.Setup(x => x.GetRequiredService<ConfigurationDbContext>()) 
    .Returns(new ConfigurationDbContext(Options, StoreOptions)); 

Mock<IServiceScope> serviceScope = new Mock<IServiceScope>(); 

serviceScope.Setup(x => x.ServiceProvider).Returns(serviceProvider.Object); 

serviceProvider.Setup(x => x.CreateScope()).Returns(serviceScope.Object); 

我收到以下錯誤:

System.NotSupportedException : Expression references a method that does not belong to the mocked object: x => x.GetRequiredService()

+0

它是一種擴展方法嗎?如果是這樣你不能moq它。 – PmanAce

+0

是的,我只是看着,它似乎是一個擴展方法。我很努力地看到我如何測試這個類,因爲它依賴於IServiceProvider。 – blgrnboy

+0

檢查此答案以找出可能的解決方案。 [嘲笑Moq的擴展方法](https://stackoverflow.com/questions/2295960/mocking-extension-methods-with-moq) – PmanAce

回答

5

如前所述,起訂量d不允許設置擴展方法。

然而在這種情況的所述延伸方法的源代碼可在Github

ServiceProviderServiceExtensions

解決這個問題的常用方法是找出擴展方法的作用,並在其執行過程中安全地模擬路徑。

所有這些的基本類型是IServiceProvider及其object Getservice(Type type)方法。此方法是解析服務類型時最終調用的方法。我們只處理抽象(接口),這使得使用moq變得更加容易。

//Arrange 
var serviceProvider = new Mock<IServiceProvider>(); 
serviceProvider 
    .Setup(x => x.GetService(typeof(ConfigurationDbContext))) 
    .Returns(new ConfigurationDbContext(Options, StoreOptions)); 

var serviceScope = new Mock<IServiceScope>(); 
serviceScope.Setup(x => x.ServiceProvider).Returns(serviceProvider.Object); 

var serviceScopeFactory = new Mock<IServiceScopeFactory>(); 
serviceScopeFactory 
    .Setup(x => x.CreateScope()) 
    .Returns(serviceScope.Object); 

serviceProvider 
    .Setup(x => x.GetService(typeof(IServiceScopeFactory))) 
    .Returns(serviceScopeFactory.Object); 

var sut = new ApiResourceRepository(serviceProvider.Object); 

//Act 
var actual = sut.Get(myIntValue); 

//Asssert 
//... 

回顧上面的代碼,你會看到如何安排滿足的擴展方法預期的行爲,並推而廣之(沒有雙關語意)下測試的方法。