Menu / szukaj

API Mock w Azure Functions

Największą zaletą Azure Functions jest skrócenie czasu, który jest potrzebny do wypuszczenia produktu na rynek. Można je również zastosować w celu przyspieszenia prototypowania aplikacji. Od jakiegoś czasu można zdefiniować mocka naszej funkcji, który w odpowiedzi na wysłane zapytanie pod konkretne API wyśle nam ustaloną odpowiedź.

Rozwiązanie to ma olbrzymi potencjał. W szczególności w przypadku różnego rodzaju prototypowania aplikacji. Wystarczy tylko zdefiniować nasz end point i wskazać jaka odpowiedź ma zostać zwrócona. Dzięki temu możemy budować od razu docelowe powiązania w naszej aplikacji. A w późniejszym etapie pracy po prostu zastąpić definicję mocka poprawnie zaimplementowaną funkcją.

Funkcjonalność ta umożliwia również zoptymalizowanie prac w zespole. Sądzę, że każdemu z nas zdarzyły się sytuacje, gdy jeden z zespołów odpowiedzialny był za front-end, drugi za back-end. Na początku prac zostały ustalone interfejsy, a po ich zakończeniu obie części aplikacji nie potrafiły się ze sobą porozumiewać. Wykorzystując to rozwiązanie możemy zdefiniować konkretne interfejsy i obydwa zespoły będą miały zmaterializowany wzór do którego będą dążyć.

Opisywana funkcjonalność nie jest jeszcze dobrze znana ponieważ nie do końca została udostępniona na Portalu Azure. Aby z niej skorzystać będziemy musieli modyfikować pliki konfiguracyjne manualnie. Czytaj dalej

Pakiet Moq.EntityFramework.Helpers

Na blogu pojawiły się ostatnio dwa wpisy pokazujące w jaki sposób mnożna zamockować DbSet<TEntity> wykorzystując Moq:

Opisane rozwiązania połączyłem w jednej bibliotece i opublikowałem jako pakiet NuGet – Moq.EntityFramework.Helpers. Czytaj dalej

EntityFramework – testowanie zapytań asynchonicznych

Jakiś czas temu opisałem w jaki sposób można zamockować typy DbContext przy pomocy MoqMockowanie typów DbContext oraz DbSet z wykorzystaniem Moq. Temat ten nie został wtedy całkowicie wyczerpany. Pozostał jeden element do opisania – zapytania asynchoroniczne. Do tego elementu chciałbym dziś wrócić.

Punktem wyjście będzie poprzedni wpis – czyli mamy fragment kodu, który pozwala na zamockowanie DbSet<T>. Teraz tylko dodamy możliwość obsługi wywołań asynchronicznych. Aby to zrobić należy zaimplementować interfejs IDbAsyncQueryProvider:

public class InMemoryAsyncQueryProvider<TEntity> : IDbAsyncQueryProvider
{
  private readonly IQueryProvider innerQueryProvider;
  
  internal InMemoryAsyncQueryProvider(IQueryProvider innerQueryProvider)
  {
    this.innerQueryProvider = innerQueryProvider;
  }

  public IQueryable CreateQuery(Expression expression)
  {
    return new InMemeoryAsyncEnumerable<TEntity>(expression);
  }

  public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
  {
    return new InMemeoryAsyncEnumerable<TElement>(expression);
  }

  public object Execute(Expression expression)
  {
    return this.innerQueryProvider.Execute(expression);
  }
  
  public TResult Execute<TResult>(Expression expression)
  {
    return this.innerQueryProvider.Execute<TResult>(expression);
  }

  public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken)
  {
    return Task.FromResult(Execute(expression));
  }

  public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
  {
    return Task.FromResult(Execute<TResult>(expression));
  }
}

Czytaj dalej

Mockowanie typów DbContext oraz DbSet z wykorzystaniem Moq

Pisząc testy jednostkowe w aplikacjach, które przechowują dane w bazie danych prędzej, czy później będziemy zmuszeni do odizolowania warstwy dostępu do bazy danych. W opisywanym przypadku jako ORM wykorzystywany jest Entity Framework.

Kod definiujący podstawowe elementy wygląda w następujący sposób:

public class User
{
  public int Id { get; set; }
  public string Login { get; set; }
  public string Name { get; set; }
  public string Surname { get; set; }
  public bool AccountLocked { get; set; }
  public virtual List<Role> Roles { get; set; }
}

public class UsersContext : DbContext
{
  public virtual DbSet<User> Users { get; set; }
  public virtual DbSet<Role> Roles { get; set; }
}

public class UsersService
{
  private readonly UsersContext usersContext;
  
  public UsersService(UsersContext usersContext)
  {
    this.usersContext = usersContext;
  }
 
  public User AddUser(string login, string name, string surname)
  {
    var newUser = this.usersContext.Users.Add(
      new User
      {
        Login = login,
        Name = name,
        Surname = surname,
        AccountLocked = false
      });
  
    this.usersContext.SaveChanges();
    return newUser;
  }
 
  public IList<User> GetLockedUsers ()
  {
    return this.usersContext.Users.Where(x => x.AccountLocked).ToList();
  }
}

Chcąc odizolować warstwę danych od aplikacji można wykorzystać jedną z dwóch opcji:

  • napisać dodatkową implementację klasy UsersContext, która na potrzeby testów jednostkowych będzie symulowała działanie bazy danych. Obiekt nowej klasy zostanie wstrzyknięty do obiektów, które do działania potrzebują klasę UsersContext.
  • wykorzystać jeden z dostępnych frameworków mockujących – w tym przypadku Moq.

Czytaj dalej