Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Autor: Tom FitzMacken
Pobieranie ukończonego projektu
W tych wskazówkach i aplikacji pokazano, jak utworzyć testy jednostkowe dla aplikacji internetowego interfejsu API 2 korzystającej z programu Entity Framework. Przedstawiono w nim sposób modyfikowania szkieletowego kontrolera w celu umożliwienia przekazywania obiektu kontekstu do testowania oraz tworzenia obiektów testowych, które współpracują z programem Entity Framework.
Aby zapoznać się z wprowadzeniem do testowania jednostkowego przy użyciu internetowego interfejsu API ASP.NET, zobacz Artykuł Unit Testing with ASP.NET Web API 2 (Testowanie jednostkowe przy użyciu internetowego interfejsu API 2).
W tym samouczku założono, że znasz podstawowe pojęcia dotyczące internetowego interfejsu API ASP.NET. Aby zapoznać się z samouczkiem wprowadzającym, zobacz Getting Started with ASP.NET Web API 2 (Wprowadzenie do internetowego interfejsu API 2).
Wersje oprogramowania używane w samouczku
- Visual Studio 2017
- Web API 2
W tym temacie
Ten temat zawiera następujące sekcje:
- Prerequisites
- Pobierz kod
- Tworzenie aplikacji przy użyciu projektu testów jednostkowych
- Tworzenie klasy modelu
- Dodawanie kontrolera
- Dodawanie wstrzykiwania zależności
- Instalowanie pakietów NuGet w projekcie testowym
- Tworzenie kontekstu testowego
- Tworzenie testów
- Uruchamianie testów
Jeśli wykonałeś już kroki opisane w artykule Testowanie jednostkowe z ASP.NET Web API 2, możesz przejść do sekcji Dodaj kontroler.
Wymagania wstępne
Visual Studio 2017 edycja Community, Professional lub Enterprise
Pobierz kod
Pobierz ukończony projekt. Projekt do pobrania zawiera kod testu jednostkowego dla tego tematu oraz temat Unit Testing ASP.NET Web API 2 .
Tworzenie aplikacji przy użyciu projektu testów jednostkowych
Projekt testu jednostkowego można utworzyć podczas tworzenia aplikacji lub dodać projekt testu jednostkowego do istniejącej aplikacji. W tym samouczku przedstawiono tworzenie projektu testów jednostkowych podczas tworzenia aplikacji.
Utwórz nową aplikację internetową ASP.NET o nazwie StoreApp.
W oknach Nowy Projekt ASP.NET wybierz szablon Pusty i dodaj foldery oraz podstawowe odwołania dla interfejsu API sieci Web. Wybierz opcję Dodaj testy jednostkowe . Projekt testu jednostkowego ma automatycznie nazwę StoreApp.Tests. Możesz zachować tę nazwę.
Po utworzeniu aplikacji zobaczysz, że zawiera ona dwa projekty — StoreApp i StoreApp.Tests.
Tworzenie klasy modelu
W projekcie StoreApp dodaj plik klasy do folderu Models o nazwie Product.cs. Zastąp zawartość pliku następującym kodem.
using System;
namespace StoreApp.Models
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
Stwórz rozwiązanie.
Dodawanie kontrolera
Kliknij prawym przyciskiem myszy folder Kontrolery i wybierz polecenie Dodaj i Nowy Element Szkieletowy. Wybierz kontroler Web API 2 z akcjami, za pomocą Entity Framework.
Ustaw następujące wartości:
- Nazwa kontrolera: ProductController
- Klasa modelu: Product
- Klasa kontekstu danych: [Wybierz przycisk Nowego kontekstu danych , który wypełnia wartości widoczne poniżej]
Kliknij przycisk Dodaj , aby utworzyć kontroler z automatycznie wygenerowanym kodem. Kod zawiera metody tworzenia, pobierania, aktualizowania i usuwania wystąpień klasy Product. Poniższy kod przedstawia metodę dodawania produktu. Zwróć uwagę, że metoda zwraca wystąpienie elementu IHttpActionResult.
// POST api/Product
[ResponseType(typeof(Product))]
public IHttpActionResult PostProduct(Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Products.Add(product);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = product.Id }, product);
}
IHttpActionResult jest jedną z nowych funkcji internetowego interfejsu API 2 i upraszcza opracowywanie testów jednostkowych.
W następnej sekcji dostosujesz wygenerowany kod, aby ułatwić przekazywanie obiektów testowych do kontrolera.
Dodaj wstrzykiwanie zależności
Obecnie klasa ProductController jest zaprogramowana na sztywno, aby używać wystąpienia klasy StoreAppContext. Użyjesz wzorca o nazwie wstrzykiwanie zależności, aby zmodyfikować aplikację i usunąć ta zakodowana zależność. Przerywając tę zależność, można przekazać pozorny obiekt podczas testowania.
Kliknij prawym przyciskiem myszy folder Models i dodaj nowy interfejs o nazwie IStoreAppContext.
Zastąp kod następującym kodem.
using System;
using System.Data.Entity;
namespace StoreApp.Models
{
public interface IStoreAppContext : IDisposable
{
DbSet<Product> Products { get; }
int SaveChanges();
void MarkAsModified(Product item);
}
}
Otwórz plik StoreAppContext.cs i wprowadź następujące wyróżnione zmiany. Ważne zmiany, które należy zwrócić uwagę, to:
- Klasa StoreAppContext implementuje interfejs IStoreAppContext
- Metoda MarkAsModified jest implementowana
using System;
using System.Data.Entity;
namespace StoreApp.Models
{
public class StoreAppContext : DbContext, IStoreAppContext
{
public StoreAppContext() : base("name=StoreAppContext")
{
}
public DbSet<Product> Products { get; set; }
public void MarkAsModified(Product item)
{
Entry(item).State = EntityState.Modified;
}
}
}
Otwórz plik ProductController.cs. Zmień istniejący kod, aby był zgodny z wyróżnionym kodem. Te zmiany znoszą zależność od StoreAppContext i umożliwiają innym klasom przekazywanie innego obiektu dla klasy kontekstu. Ta zmiana umożliwi przekazanie kontekstu testowego podczas testów jednostkowych.
public class ProductController : ApiController
{
// modify the type of the db field
private IStoreAppContext db = new StoreAppContext();
// add these constructors
public ProductController() { }
public ProductController(IStoreAppContext context)
{
db = context;
}
// rest of class not shown
}
Istnieje jeszcze jedna zmiana, którą należy wprowadzić w productController. W metodzie PutProduct zastąp wiersz, który ustawia stan jednostki na zmodyfikowany za pomocą wywołania metody MarkAsModified.
// PUT api/Product/5
public IHttpActionResult PutProduct(int id, Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != product.Id)
{
return BadRequest();
}
//db.Entry(product).State = EntityState.Modified;
db.MarkAsModified(product);
// rest of method not shown
}
Stwórz rozwiązanie.
Teraz możesz przystąpić do konfigurowania projektu testowego.
Instalowanie pakietów NuGet w projekcie testowym
Jeśli używasz szablonu Empty do utworzenia aplikacji, projekt testu jednostkowego (StoreApp.Tests) nie zawiera żadnych zainstalowanych pakietów NuGet. Inne szablony, takie jak szablon internetowego interfejsu API, zawierają niektóre pakiety NuGet w projekcie testów jednostkowych. Na potrzeby tego samouczka należy dołączyć pakiet Entity Framework i pakiet Microsoft ASP.NET Web API 2 Core do projektu testowego.
Kliknij prawym przyciskiem myszy projekt StoreApp.Tests i wybierz pozycję Zarządzaj pakietami NuGet. Musisz wybrać projekt StoreApp.Tests, aby dodać pakiety do tego projektu.
W pakietach online znajdź i zainstaluj pakiet EntityFramework (wersja 6.0 lub nowsza). Jeśli okaże się, że pakiet EntityFramework jest już zainstalowany, być może wybrano projekt StoreApp zamiast projektu StoreApp.Tests.
Znajdź i zainstaluj pakiet Microsoft ASP.NET Web API 2 Core.
Zamknij okno Zarządzanie pakietami NuGet.
Tworzenie kontekstu testowego
Dodaj klasę o nazwie TestDbSet do projektu testowego. Ta klasa służy jako klasa bazowa dla zestawu danych testowych. Zastąp kod następującym kodem.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Linq;
namespace StoreApp.Tests
{
public class TestDbSet<T> : DbSet<T>, IQueryable, IEnumerable<T>
where T : class
{
ObservableCollection<T> _data;
IQueryable _query;
public TestDbSet()
{
_data = new ObservableCollection<T>();
_query = _data.AsQueryable();
}
public override T Add(T item)
{
_data.Add(item);
return item;
}
public override T Remove(T item)
{
_data.Remove(item);
return item;
}
public override T Attach(T item)
{
_data.Add(item);
return item;
}
public override T Create()
{
return Activator.CreateInstance<T>();
}
public override TDerivedEntity Create<TDerivedEntity>()
{
return Activator.CreateInstance<TDerivedEntity>();
}
public override ObservableCollection<T> Local
{
get { return new ObservableCollection<T>(_data); }
}
Type IQueryable.ElementType
{
get { return _query.ElementType; }
}
System.Linq.Expressions.Expression IQueryable.Expression
{
get { return _query.Expression; }
}
IQueryProvider IQueryable.Provider
{
get { return _query.Provider; }
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _data.GetEnumerator();
}
}
}
Dodaj klasę o nazwie TestProductDbSet do projektu testowego zawierającego następujący kod.
using System;
using System.Linq;
using StoreApp.Models;
namespace StoreApp.Tests
{
class TestProductDbSet : TestDbSet<Product>
{
public override Product Find(params object[] keyValues)
{
return this.SingleOrDefault(product => product.Id == (int)keyValues.Single());
}
}
}
Dodaj klasę o nazwie TestStoreAppContext i zastąp istniejący kod następującym kodem.
using System;
using System.Data.Entity;
using StoreApp.Models;
namespace StoreApp.Tests
{
public class TestStoreAppContext : IStoreAppContext
{
public TestStoreAppContext()
{
this.Products = new TestProductDbSet();
}
public DbSet<Product> Products { get; set; }
public int SaveChanges()
{
return 0;
}
public void MarkAsModified(Product item) { }
public void Dispose() { }
}
}
Tworzenie testów
Domyślnie projekt testowy zawiera pusty plik testowy o nazwie UnitTest1.cs. Ten plik przedstawia atrybuty używane do tworzenia metod testowych. Na potrzeby tego samouczka możesz usunąć ten plik, ponieważ dodasz nową klasę testową.
Dodaj klasę o nazwie TestProductController do projektu testowego. Zastąp kod następującym kodem.
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web.Http.Results;
using System.Net;
using StoreApp.Models;
using StoreApp.Controllers;
namespace StoreApp.Tests
{
[TestClass]
public class TestProductController
{
[TestMethod]
public void PostProduct_ShouldReturnSameProduct()
{
var controller = new ProductController(new TestStoreAppContext());
var item = GetDemoProduct();
var result =
controller.PostProduct(item) as CreatedAtRouteNegotiatedContentResult<Product>;
Assert.IsNotNull(result);
Assert.AreEqual(result.RouteName, "DefaultApi");
Assert.AreEqual(result.RouteValues["id"], result.Content.Id);
Assert.AreEqual(result.Content.Name, item.Name);
}
[TestMethod]
public void PutProduct_ShouldReturnStatusCode()
{
var controller = new ProductController(new TestStoreAppContext());
var item = GetDemoProduct();
var result = controller.PutProduct(item.Id, item) as StatusCodeResult;
Assert.IsNotNull(result);
Assert.IsInstanceOfType(result, typeof(StatusCodeResult));
Assert.AreEqual(HttpStatusCode.NoContent, result.StatusCode);
}
[TestMethod]
public void PutProduct_ShouldFail_WhenDifferentID()
{
var controller = new ProductController(new TestStoreAppContext());
var badresult = controller.PutProduct(999, GetDemoProduct());
Assert.IsInstanceOfType(badresult, typeof(BadRequestResult));
}
[TestMethod]
public void GetProduct_ShouldReturnProductWithSameID()
{
var context = new TestStoreAppContext();
context.Products.Add(GetDemoProduct());
var controller = new ProductController(context);
var result = controller.GetProduct(3) as OkNegotiatedContentResult<Product>;
Assert.IsNotNull(result);
Assert.AreEqual(3, result.Content.Id);
}
[TestMethod]
public void GetProducts_ShouldReturnAllProducts()
{
var context = new TestStoreAppContext();
context.Products.Add(new Product { Id = 1, Name = "Demo1", Price = 20 });
context.Products.Add(new Product { Id = 2, Name = "Demo2", Price = 30 });
context.Products.Add(new Product { Id = 3, Name = "Demo3", Price = 40 });
var controller = new ProductController(context);
var result = controller.GetProducts() as TestProductDbSet;
Assert.IsNotNull(result);
Assert.AreEqual(3, result.Local.Count);
}
[TestMethod]
public void DeleteProduct_ShouldReturnOK()
{
var context = new TestStoreAppContext();
var item = GetDemoProduct();
context.Products.Add(item);
var controller = new ProductController(context);
var result = controller.DeleteProduct(3) as OkNegotiatedContentResult<Product>;
Assert.IsNotNull(result);
Assert.AreEqual(item.Id, result.Content.Id);
}
Product GetDemoProduct()
{
return new Product() { Id = 3, Name = "Demo name", Price = 5 };
}
}
}
Uruchamianie testów
Teraz możesz uruchomić testy. Wszystkie metody oznaczone atrybutem TestMethod zostaną przetestowane. W elemencie menu Test uruchom testy.
Otwórz okno Eksplorator testów i zwróć uwagę na wyniki testów.