2014-12-15 15 views
12

mam tej metody:Testowanie EF metody asynchroniczne z metod synchronizacji z MOQ

public async Task DeleteUserAsync(Guid userId) 
    { 
     using (var context = this.contextFactory.Create()) 
     { 
      var user = await context.Users.FirstOrDefaultAsync(x => x.Id.Equals(userId)); 

      if (user == null) 
      { 
       throw new Exception("User doesn't exist"); 
      } 

      context.Users.Remove(user); 

      await context.SaveChangesAsync(); 
     } 
    } 

Chcę przetestować go. Więc tworzę test:

[TestMethod] 
    public async Task DeleteUsersSuccessfulCallTest() 
    { 
     // Arrange 
     var id = Guid.NewGuid(); 
     var user = new User() { Id = id }; 

     var context = new Mock<IDashboardContext>(); 
     var usersDbSet = DbSetQueryMocking.GenericSetupAsyncQueryableMockInterfaceSet(new List<User> { user }.AsQueryable()); 
     context.Setup(x => x.Users).Returns(usersDbSet.Object); 

     context.Setup(x => x.Users.Remove(user)).Returns(user).Verifiable(); 
     context.Setup(x => x.SaveChangesAsync()).ReturnsAsync(1).Verifiable(); 

     this.contextFactory.Setup(x => x.Create()).Returns(context.Object); 

     // Act 
     await this.userService.DeleteUserAsync(id); 

     context.VerifyAll(); 
    } 
} 

Mam tej metody, aby stworzyć mi próbny zestaw:

public static Mock<DbSet<T>> GenericSetupAsyncQueryableMockSet<T>(IQueryable<T> data) where T : class 
    { 
     var mockSet = new Mock<DbSet<T>>(); 
     mockSet.As<IDbAsyncEnumerable<T>>().Setup(m => m.GetAsyncEnumerator()).Returns(new TestDbAsyncEnumerator<T>(data.GetEnumerator())); 
     mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(new TestDbAsyncQueryProvider<T>(data.Provider)); 
     mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression); 
     mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType); 
     mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator()); 

     return mockSet; 
    } 

Jednakże, ponieważ moja DeleteUserAsync zawiera metody rozszerzenie async i standardowych metod synchronizacji otrzymuję komunikat o błędzie :

System.InvalidOperationException: dostawca dla źródłowego produktu IQueryable nie implementuje obiektu IDbAsyncQueryProvider. Tylko dostawcy implementujący IDbAsyncQueryProvider mogą być używane do asynchronicznych operacji Entity Framework. Aby uzyskać więcej informacji, patrz http://go.microsoft.com/fwlink/?LinkId=287068.

Oczywiście gdybym tylko skonfigurować DbSet<T> z Queryable wyśmiewali się wtedy będzie rzucać ten sam wyjątek.

FYI: linia wykraczająca jest:

context.Setup(x => x.Users.Remove(user)).Returns(user).Verifiable(); 

Z tej linii: błędy

Bez niej: udane testy.

Jak to naprawić?

+0

To najprawdopodobniej problem z szyderstwem i nie ma nic wspólnego z EF ani testowaniem. – Euphoric

+0

Mam zaktualizowane pytanie odzwierciedlające ten –

+0

https://msdn.microsoft.com/en-us/data/dn314429#async – Ali

Odpowiedz

11

Klasa EnumerableQuery<T>, która jest produkowana przez .AsQueryable(), nie implementuje IDbAsyncQueryProvider, ale można ją łatwo rozszerzyć o implementację EnumerableQuery<T>. Utwórz jeden z nich zamiast dzwonić pod numer .AsQueryable(), aby otoczyć swoją kolekcję. Mam poniżej implementację, która rozszerza ją dalej do IDbSet<T>, ale nie musisz iść tak daleko.

class StubSet<T> : EnumerableQuery<T>, IDbSet<T>, IDbAsyncQueryProvider 
    where T : class 
{ 
    public StubSet(IEnumerable<T> collection) : base(collection) 
    { 
     Local = new ObservableCollection<T>(collection); 
    } 

    public ObservableCollection<T> Local { get; private set; } 

    public T Find(params object[] keyValues) 
    { 
     throw new NotImplementedException(); 
    } 

    public T Add(T entity) 
    { 
     Local.Add(entity); 
     return entity; 
    } 

    public T Remove(T entity) 
    { 
     Local.Remove(entity); 
     return entity; 
    } 

    public T Attach(T entity) 
    { 
     return Add(entity); 
    } 

    public T Create() 
    { 
     throw new NotImplementedException(); 
    } 

    public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T 
    { 
     throw new NotImplementedException(); 
    } 

    public void DeleteObject(T entity) 
    { 
     throw new NotImplementedException(); 
    } 

    public void Detach(T entity) 
    { 
     throw new NotImplementedException(); 
    }   

    async Task<object> IDbAsyncQueryProvider.ExecuteAsync(Expression expression, CancellationToken cancellationToken) 
    { 
     return ((IQueryProvider)this).Execute(expression); 
    } 

    async Task<TResult> IDbAsyncQueryProvider.ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken) 
    { 
     return ((IQueryProvider)this).Execute<TResult>(expression); 
    } 
} 
+6

Ten artykuł w witrynie MSDN wydaje się być Twoim źródłem: https://msdn.microsoft.com/pl -us/library/dn314429.aspx Publikowanie go z pewnością pomoże innym. –

Powiązane problemy