Zdarzenia
19 lis, 23 - 21 lis, 23
Dołącz do sesji online na konferencji Microsoft Ignite, aby rozwinąć swoje umiejętności i pomóc w rozwiązywaniu dzisiejszych złożonych problemów.
Zarejestruj się terazTa przeglądarka nie jest już obsługiwana.
Przejdź na przeglądarkę Microsoft Edge, aby korzystać z najnowszych funkcji, aktualizacji zabezpieczeń i pomocy technicznej.
ASP.NET Core obsługuje testy jednostkowe Razor aplikacji Pages. Testy warstwy dostępu do danych (DAL) i modeli stron pomagają zapewnić:
W tym temacie założono, że masz podstawową wiedzę na temat Razor aplikacji Pages i testów jednostkowych. Jeśli nie Razor znasz aplikacji Stron lub pojęć dotyczących testowania, zobacz następujące tematy:
Wyświetl lub pobierz przykładowy kod (jak pobrać)
Przykładowy projekt składa się z dwóch aplikacji:
Aplikacja | Folder projektu | opis |
---|---|---|
Aplikacja komunikatów | src/RazorPagesTestSample | Umożliwia użytkownikowi dodawanie komunikatu, usuwanie jednej wiadomości, usuwanie wszystkich komunikatów i analizowanie komunikatów (znajdowanie średniej liczby słów na wiadomość). |
Testowanie aplikacji | tests/RazorPagesTestSample.Tests | Służy do testowania jednostkowego modelu strony DAL i indeksu aplikacji komunikatów. |
Testy można uruchamiać przy użyciu wbudowanych funkcji testowych środowiska IDE, takich jak Visual Studio. Jeśli używasz programu Visual Studio Code lub wiersza polecenia, wykonaj następujące polecenie w wierszu polecenia w folderze tests/RazorPagesTestSample.Tests :
dotnet test
Aplikacja komunikatów to Razor system komunikatów Pages o następujących cechach:
Pages/Index.cshtml
i Pages/Index.cshtml.cs
) udostępnia metody interfejsu użytkownika i modelu strony do kontrolowania dodawania, usuwania i analizowania komunikatów (znajdowanie średniej liczby słów na komunikat).Message
(Data/Message.cs
) z dwiema właściwościami: Id
(klucz) i Text
(komunikat). Właściwość jest wymagana Text
i ograniczona do 200 znaków.AppDbContext
kontekstu bazy danych (Data/AppDbContext.cs
). Metody DAL są oznaczone jako virtual
, co umożliwia wyśmiewanie metod do użycia w testach.† Temat ef, Test with InMemory, wyjaśnia, jak używać bazy danych w pamięci do testów przy użyciu narzędzia MSTest. W tym temacie jest używana struktura testowa xUnit . Koncepcje testów i implementacje testów w różnych platformach testowych są podobne, ale nie identyczne.
Mimo że przykładowa aplikacja nie używa wzorca repozytorium i nie jest skutecznym przykładem wzorca Unit of Work (UoW), Razor strony obsługują te wzorce programowania. Aby uzyskać więcej informacji, zobacz Projektowanie warstwy trwałości infrastruktury i logiki kontrolera testów w programie ASP.NET Core (przykład implementuje wzorzec repozytorium).
Aplikacja testowa jest aplikacją konsolową wewnątrz folderu tests/RazorPagesTestSample.Tests .
Folder aplikacji testowej | opis |
---|---|
UnitTests |
|
Narzędzia | Zawiera metodę TestDbContextOptions używaną do tworzenia nowych opcji kontekstu bazy danych dla każdego testu jednostkowego DAL, dzięki czemu baza danych zostanie zresetowana do stanu odniesienia dla każdego testu. |
Struktura testowa to xUnit. Struktura pozorowania obiektów to Moq.
Aplikacja komunikatów ma dal z czterema metodami zawartymi AppDbContext
w klasie (src/RazorPagesTestSample/Data/AppDbContext.cs
). Każda metoda ma jeden lub dwa testy jednostkowe w aplikacji testowej.
DAL, metoda | Function |
---|---|
GetMessagesAsync |
Uzyskuje element List<Message> z bazy danych posortowany według Text właściwości . |
AddMessageAsync |
Dodaje element Message do bazy danych. |
DeleteAllMessagesAsync |
Usuwa wszystkie Message wpisy z bazy danych. |
DeleteMessageAsync |
Usuwa pojedynczy element Message z bazy danych za pomocą polecenia Id . |
Testy jednostkowe dal wymagają DbContextOptions utworzenia nowego AppDbContext
dla każdego testu. Jednym z podejść do tworzenia DbContextOptions
elementu dla każdego testu jest użycie elementu DbContextOptionsBuilder:
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb");
using (var db = new AppDbContext(optionsBuilder.Options))
{
// Use the db here in the unit test.
}
Problem z tym podejściem polega na tym, że każdy test odbiera bazę danych w każdym stanie, w jakim opuścił poprzedni test. Może to być problematyczne podczas próby zapisania niepodzielnych testów jednostkowych, które nie zakłócają siebie nawzajem. Aby wymusić AppDbContext
użycie nowego kontekstu bazy danych dla każdego testu, podaj DbContextOptions
wystąpienie oparte na nowym dostawcy usług. Aplikacja testowa pokazuje, jak to zrobić przy użyciu metody Utilities
TestDbContextOptions
klasy (tests/RazorPagesTestSample.Tests/Utilities/Utilities.cs
):
public static DbContextOptions<AppDbContext> TestDbContextOptions()
{
// Create a new service provider to create a new in-memory database.
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
// Create a new options instance using an in-memory database and
// IServiceProvider that the context should resolve all of its
// services from.
var builder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb")
.UseInternalServiceProvider(serviceProvider);
return builder.Options;
}
Użycie w DbContextOptions
testach jednostkowych DAL umożliwia wykonywanie każdego testu niepodziealnie przy użyciu nowego wystąpienia bazy danych:
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Use the db here in the unit test.
}
Każda metoda testowa w DataAccessLayerTest
klasie (UnitTests/DataAccessLayerTest.cs
) jest zgodna z podobnym wzorcem Arrange-Act-Assert:
Na przykład DeleteMessageAsync
metoda jest odpowiedzialna za usunięcie pojedynczego komunikatu zidentyfikowanego przez element Id
(src/RazorPagesTestSample/Data/AppDbContext.cs
):
public async virtual Task DeleteMessageAsync(int id)
{
var message = await Messages.FindAsync(id);
if (message != null)
{
Messages.Remove(message);
await SaveChangesAsync();
}
}
Istnieją dwa testy dla tej metody. Jeden test sprawdza, czy metoda usuwa komunikat, gdy komunikat znajduje się w bazie danych. Inna metoda sprawdza, czy baza danych nie zmienia się, jeśli komunikat Id
o usunięciu nie istnieje. Poniżej DeleteMessageAsync_MessageIsDeleted_WhenMessageIsFound
przedstawiono metodę:
[Fact]
public async Task DeleteMessageAsync_MessageIsDeleted_WhenMessageIsFound()
{
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Arrange
var seedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(seedMessages);
await db.SaveChangesAsync();
var recId = 1;
var expectedMessages =
seedMessages.Where(message => message.Id != recId).ToList();
// Act
await db.DeleteMessageAsync(recId);
// Assert
var actualMessages = await db.Messages.AsNoTracking().ToListAsync();
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
}
}
Najpierw metoda wykonuje krok Rozmieść, w którym odbywa się przygotowanie do wykonania kroku aktu. Komunikaty rozmieszczania są uzyskiwane i przechowywane w elemencie seedMessages
. Komunikaty rozmieszczania są zapisywane w bazie danych. Komunikat z elementem Id
1
jest ustawiony do usunięcia. Po wykonaniu DeleteMessageAsync
metody oczekiwane komunikaty powinny mieć wszystkie komunikaty z wyjątkiem tego, który ma Id
1
wartość . Zmienna expectedMessages
reprezentuje ten oczekiwany wynik.
// Arrange
var seedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(seedMessages);
await db.SaveChangesAsync();
var recId = 1;
var expectedMessages =
seedMessages.Where(message => message.Id != recId).ToList();
Metoda działa: DeleteMessageAsync
metoda jest wykonywana przekazując w elemecie recId
elementu 1
:
// Act
await db.DeleteMessageAsync(recId);
Na koniec metoda uzyskuje Messages
element z kontekstu i porównuje go z expectedMessages
twierdzeniem, że te dwie są równe:
// Assert
var actualMessages = await db.Messages.AsNoTracking().ToListAsync();
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
Aby porównać te dwa elementy List<Message>
są takie same:
Id
.Text
.Podobna metoda DeleteMessageAsync_NoMessageIsDeleted_WhenMessageIsNotFound
testowa sprawdza wynik próby usunięcia komunikatu, który nie istnieje. W takim przypadku oczekiwane komunikaty w bazie danych powinny być równe rzeczywistym komunikatom po wykonaniu DeleteMessageAsync
metody. Nie należy zmieniać zawartości bazy danych:
[Fact]
public async Task DeleteMessageAsync_NoMessageIsDeleted_WhenMessageIsNotFound()
{
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Arrange
var expectedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(expectedMessages);
await db.SaveChangesAsync();
var recId = 4;
// Act
try
{
await db.DeleteMessageAsync(recId);
}
catch
{
// recId doesn't exist
}
// Assert
var actualMessages = await db.Messages.AsNoTracking().ToListAsync();
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
}
}
Inny zestaw testów jednostkowych jest odpowiedzialny za testy metod modelu strony. W aplikacji komunikatów modele strony Indeks znajdują się w klasie w pliku IndexModel
src/RazorPagesTestSample/Pages/Index.cshtml.cs
.
Metoda modelu strony | Function |
---|---|
OnGetAsync |
Uzyskuje komunikaty z dal dla interfejsu użytkownika przy użyciu GetMessagesAsync metody . |
OnPostAddMessageAsync |
Jeśli parametr ModelState jest prawidłowy, wywołania AddMessageAsync w celu dodania komunikatu do bazy danych. |
OnPostDeleteAllMessagesAsync |
Wywołuje metodę DeleteAllMessagesAsync usuwania wszystkich komunikatów w bazie danych. |
OnPostDeleteMessageAsync |
DeleteMessageAsync Wykonuje polecenie , aby usunąć komunikat z określoną wartościąId . |
OnPostAnalyzeMessagesAsync |
Jeśli co najmniej jeden komunikat znajduje się w bazie danych, oblicza średnią liczbę wyrazów na komunikat. |
Metody modelu strony są testowane przy użyciu siedmiu testów w IndexPageTests
klasie (tests/RazorPagesTestSample.Tests/UnitTests/IndexPageTests.cs
). Testy używają znanego wzorca Arrange-Assert-Act. Te testy koncentrują się na:
Ta grupa testów często wyśmiewa metody dal w celu wygenerowania oczekiwanych danych dla kroku Act, w którym jest wykonywana metoda modelu strony. Na przykład GetMessagesAsync
metoda AppDbContext
metody jest wyśmiewany w celu wygenerowania danych wyjściowych. Gdy metoda modelu strony wykonuje tę metodę, pozorowanie zwraca wynik. Dane nie pochodzą z bazy danych. Spowoduje to utworzenie przewidywalnych, niezawodnych warunków testowych na potrzeby korzystania z dal w testach modelu strony.
Test OnGetAsync_PopulatesThePageModel_WithAListOfMessages
pokazuje, jak GetMessagesAsync
metoda jest wyśmiewany dla modelu strony:
var mockAppDbContext = new Mock<AppDbContext>(optionsBuilder.Options);
var expectedMessages = AppDbContext.GetSeedingMessages();
mockAppDbContext.Setup(
db => db.GetMessagesAsync()).Returns(Task.FromResult(expectedMessages));
var pageModel = new IndexModel(mockAppDbContext.Object);
OnGetAsync
Gdy metoda jest wykonywana w kroku Act, wywołuje metodę modelu GetMessagesAsync
strony.
Krok działania testu jednostkowego (tests/RazorPagesTestSample.Tests/UnitTests/IndexPageTests.cs
):
// Act
await pageModel.OnGetAsync();
IndexPage
metoda modelu OnGetAsync
strony (src/RazorPagesTestSample/Pages/Index.cshtml.cs
):
public async Task OnGetAsync()
{
Messages = await _db.GetMessagesAsync();
}
Metoda GetMessagesAsync
w dal nie zwraca wyniku dla tego wywołania metody. Wyśmiewany wersja metody zwraca wynik.
Assert
W kroku rzeczywiste komunikaty (actualMessages
) są przypisywane z Messages
właściwości modelu strony. Sprawdzanie typu jest również wykonywane po przypisaniu komunikatów. Oczekiwane i rzeczywiste komunikaty są porównywane przez ich Text
właściwości. Test potwierdza, że dwa List<Message>
wystąpienia zawierają te same komunikaty.
// Assert
var actualMessages = Assert.IsAssignableFrom<List<Message>>(pageModel.Messages);
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
Inne testy w tej grupie tworzą obiekty modelu strony, które obejmują DefaultHttpContext, ModelStateDictionary, an ActionContext do ustanowienia PageContext
, , ViewDataDictionary
i PageContext
. Są one przydatne podczas przeprowadzania testów. Na przykład aplikacja komunikatu ModelState
ustanawia błąd, AddModelError aby sprawdzić, czy podczas wykonywania jest zwracany OnPostAddMessageAsync
prawidłowy PageResult element:
[Fact]
public async Task OnPostAddMessageAsync_ReturnsAPageResult_WhenModelStateIsInvalid()
{
// Arrange
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb");
var mockAppDbContext = new Mock<AppDbContext>(optionsBuilder.Options);
var expectedMessages = AppDbContext.GetSeedingMessages();
mockAppDbContext.Setup(db => db.GetMessagesAsync()).Returns(Task.FromResult(expectedMessages));
var httpContext = new DefaultHttpContext();
var modelState = new ModelStateDictionary();
var actionContext = new ActionContext(httpContext, new RouteData(), new PageActionDescriptor(), modelState);
var modelMetadataProvider = new EmptyModelMetadataProvider();
var viewData = new ViewDataDictionary(modelMetadataProvider, modelState);
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>());
var pageContext = new PageContext(actionContext)
{
ViewData = viewData
};
var pageModel = new IndexModel(mockAppDbContext.Object)
{
PageContext = pageContext,
TempData = tempData,
Url = new UrlHelper(actionContext)
};
pageModel.ModelState.AddModelError("Message.Text", "The Text field is required.");
// Act
var result = await pageModel.OnPostAddMessageAsync();
// Assert
Assert.IsType<PageResult>(result);
}
ASP.NET Core obsługuje testy jednostkowe Razor aplikacji Pages. Testy warstwy dostępu do danych (DAL) i modeli stron pomagają zapewnić:
W tym temacie założono, że masz podstawową wiedzę na temat Razor aplikacji Pages i testów jednostkowych. Jeśli nie Razor znasz aplikacji Stron lub pojęć dotyczących testowania, zobacz następujące tematy:
Wyświetl lub pobierz przykładowy kod (jak pobrać)
Przykładowy projekt składa się z dwóch aplikacji:
Aplikacja | Folder projektu | opis |
---|---|---|
Aplikacja komunikatów | src/RazorPagesTestSample | Umożliwia użytkownikowi dodawanie komunikatu, usuwanie jednej wiadomości, usuwanie wszystkich komunikatów i analizowanie komunikatów (znajdowanie średniej liczby słów na wiadomość). |
Testowanie aplikacji | tests/RazorPagesTestSample.Tests | Służy do testowania jednostkowego modelu strony DAL i indeksu aplikacji komunikatów. |
Testy można uruchamiać przy użyciu wbudowanych funkcji testowych środowiska IDE, takich jak Visual Studio. Jeśli używasz programu Visual Studio Code lub wiersza polecenia, wykonaj następujące polecenie w wierszu polecenia w folderze tests/RazorPagesTestSample.Tests :
dotnet test
Aplikacja komunikatów to Razor system komunikatów Pages o następujących cechach:
Pages/Index.cshtml
i Pages/Index.cshtml.cs
) udostępnia metody interfejsu użytkownika i modelu strony do kontrolowania dodawania, usuwania i analizowania komunikatów (znajdowanie średniej liczby słów na komunikat).Message
(Data/Message.cs
) z dwiema właściwościami: Id
(klucz) i Text
(komunikat). Właściwość jest wymagana Text
i ograniczona do 200 znaków.AppDbContext
kontekstu bazy danych (Data/AppDbContext.cs
). Metody DAL są oznaczone jako virtual
, co umożliwia wyśmiewanie metod do użycia w testach.† Temat ef, Test with InMemory, wyjaśnia, jak używać bazy danych w pamięci do testów przy użyciu narzędzia MSTest. W tym temacie jest używana struktura testowa xUnit . Koncepcje testów i implementacje testów w różnych platformach testowych są podobne, ale nie identyczne.
Mimo że przykładowa aplikacja nie używa wzorca repozytorium i nie jest skutecznym przykładem wzorca Unit of Work (UoW), Razor strony obsługują te wzorce programowania. Aby uzyskać więcej informacji, zobacz Projektowanie warstwy trwałości infrastruktury i logiki kontrolera testów w programie ASP.NET Core (przykład implementuje wzorzec repozytorium).
Aplikacja testowa jest aplikacją konsolową wewnątrz folderu tests/RazorPagesTestSample.Tests .
Folder aplikacji testowej | opis |
---|---|
UnitTests |
|
Narzędzia | Zawiera metodę TestDbContextOptions używaną do tworzenia nowych opcji kontekstu bazy danych dla każdego testu jednostkowego DAL, dzięki czemu baza danych zostanie zresetowana do stanu odniesienia dla każdego testu. |
Struktura testowa to xUnit. Struktura pozorowania obiektów to Moq.
Aplikacja komunikatów ma dal z czterema metodami zawartymi AppDbContext
w klasie (src/RazorPagesTestSample/Data/AppDbContext.cs
). Każda metoda ma jeden lub dwa testy jednostkowe w aplikacji testowej.
DAL, metoda | Function |
---|---|
GetMessagesAsync |
Uzyskuje element List<Message> z bazy danych posortowany według Text właściwości . |
AddMessageAsync |
Dodaje element Message do bazy danych. |
DeleteAllMessagesAsync |
Usuwa wszystkie Message wpisy z bazy danych. |
DeleteMessageAsync |
Usuwa pojedynczy element Message z bazy danych za pomocą polecenia Id . |
Testy jednostkowe dal wymagają DbContextOptions utworzenia nowego AppDbContext
dla każdego testu. Jednym z podejść do tworzenia DbContextOptions
elementu dla każdego testu jest użycie elementu DbContextOptionsBuilder:
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb");
using (var db = new AppDbContext(optionsBuilder.Options))
{
// Use the db here in the unit test.
}
Problem z tym podejściem polega na tym, że każdy test odbiera bazę danych w każdym stanie, w jakim opuścił poprzedni test. Może to być problematyczne podczas próby zapisania niepodzielnych testów jednostkowych, które nie zakłócają siebie nawzajem. Aby wymusić AppDbContext
użycie nowego kontekstu bazy danych dla każdego testu, podaj DbContextOptions
wystąpienie oparte na nowym dostawcy usług. Aplikacja testowa pokazuje, jak to zrobić przy użyciu metody Utilities
TestDbContextOptions
klasy (tests/RazorPagesTestSample.Tests/Utilities/Utilities.cs
):
public static DbContextOptions<AppDbContext> TestDbContextOptions()
{
// Create a new service provider to create a new in-memory database.
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
// Create a new options instance using an in-memory database and
// IServiceProvider that the context should resolve all of its
// services from.
var builder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb")
.UseInternalServiceProvider(serviceProvider);
return builder.Options;
}
Użycie w DbContextOptions
testach jednostkowych DAL umożliwia wykonywanie każdego testu niepodziealnie przy użyciu nowego wystąpienia bazy danych:
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Use the db here in the unit test.
}
Każda metoda testowa w DataAccessLayerTest
klasie (UnitTests/DataAccessLayerTest.cs
) jest zgodna z podobnym wzorcem Arrange-Act-Assert:
Na przykład DeleteMessageAsync
metoda jest odpowiedzialna za usunięcie pojedynczego komunikatu zidentyfikowanego przez element Id
(src/RazorPagesTestSample/Data/AppDbContext.cs
):
public async virtual Task DeleteMessageAsync(int id)
{
var message = await Messages.FindAsync(id);
if (message != null)
{
Messages.Remove(message);
await SaveChangesAsync();
}
}
Istnieją dwa testy dla tej metody. Jeden test sprawdza, czy metoda usuwa komunikat, gdy komunikat znajduje się w bazie danych. Inna metoda sprawdza, czy baza danych nie zmienia się, jeśli komunikat Id
o usunięciu nie istnieje. Poniżej DeleteMessageAsync_MessageIsDeleted_WhenMessageIsFound
przedstawiono metodę:
[Fact]
public async Task DeleteMessageAsync_MessageIsDeleted_WhenMessageIsFound()
{
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Arrange
var seedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(seedMessages);
await db.SaveChangesAsync();
var recId = 1;
var expectedMessages =
seedMessages.Where(message => message.Id != recId).ToList();
// Act
await db.DeleteMessageAsync(recId);
// Assert
var actualMessages = await db.Messages.AsNoTracking().ToListAsync();
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
}
}
Najpierw metoda wykonuje krok Rozmieść, w którym odbywa się przygotowanie do wykonania kroku aktu. Komunikaty rozmieszczania są uzyskiwane i przechowywane w elemencie seedMessages
. Komunikaty rozmieszczania są zapisywane w bazie danych. Komunikat z elementem Id
1
jest ustawiony do usunięcia. Po wykonaniu DeleteMessageAsync
metody oczekiwane komunikaty powinny mieć wszystkie komunikaty z wyjątkiem tego, który ma Id
1
wartość . Zmienna expectedMessages
reprezentuje ten oczekiwany wynik.
// Arrange
var seedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(seedMessages);
await db.SaveChangesAsync();
var recId = 1;
var expectedMessages =
seedMessages.Where(message => message.Id != recId).ToList();
Metoda działa: DeleteMessageAsync
metoda jest wykonywana przekazując w elemecie recId
elementu 1
:
// Act
await db.DeleteMessageAsync(recId);
Na koniec metoda uzyskuje Messages
element z kontekstu i porównuje go z expectedMessages
twierdzeniem, że te dwie są równe:
// Assert
var actualMessages = await db.Messages.AsNoTracking().ToListAsync();
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
Aby porównać te dwa elementy List<Message>
są takie same:
Id
.Text
.Podobna metoda DeleteMessageAsync_NoMessageIsDeleted_WhenMessageIsNotFound
testowa sprawdza wynik próby usunięcia komunikatu, który nie istnieje. W takim przypadku oczekiwane komunikaty w bazie danych powinny być równe rzeczywistym komunikatom po wykonaniu DeleteMessageAsync
metody. Nie należy zmieniać zawartości bazy danych:
[Fact]
public async Task DeleteMessageAsync_NoMessageIsDeleted_WhenMessageIsNotFound()
{
using (var db = new AppDbContext(Utilities.TestDbContextOptions()))
{
// Arrange
var expectedMessages = AppDbContext.GetSeedingMessages();
await db.AddRangeAsync(expectedMessages);
await db.SaveChangesAsync();
var recId = 4;
// Act
await db.DeleteMessageAsync(recId);
// Assert
var actualMessages = await db.Messages.AsNoTracking().ToListAsync();
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
}
}
Inny zestaw testów jednostkowych jest odpowiedzialny za testy metod modelu strony. W aplikacji komunikatów modele strony Indeks znajdują się w klasie w pliku IndexModel
src/RazorPagesTestSample/Pages/Index.cshtml.cs
.
Metoda modelu strony | Function |
---|---|
OnGetAsync |
Uzyskuje komunikaty z dal dla interfejsu użytkownika przy użyciu GetMessagesAsync metody . |
OnPostAddMessageAsync |
Jeśli parametr ModelState jest prawidłowy, wywołania AddMessageAsync w celu dodania komunikatu do bazy danych. |
OnPostDeleteAllMessagesAsync |
Wywołuje metodę DeleteAllMessagesAsync usuwania wszystkich komunikatów w bazie danych. |
OnPostDeleteMessageAsync |
DeleteMessageAsync Wykonuje polecenie , aby usunąć komunikat z określoną wartościąId . |
OnPostAnalyzeMessagesAsync |
Jeśli co najmniej jeden komunikat znajduje się w bazie danych, oblicza średnią liczbę wyrazów na komunikat. |
Metody modelu strony są testowane przy użyciu siedmiu testów w IndexPageTests
klasie (tests/RazorPagesTestSample.Tests/UnitTests/IndexPageTests.cs
). Testy używają znanego wzorca Arrange-Assert-Act. Te testy koncentrują się na:
Ta grupa testów często wyśmiewa metody dal w celu wygenerowania oczekiwanych danych dla kroku Act, w którym jest wykonywana metoda modelu strony. Na przykład GetMessagesAsync
metoda AppDbContext
metody jest wyśmiewany w celu wygenerowania danych wyjściowych. Gdy metoda modelu strony wykonuje tę metodę, pozorowanie zwraca wynik. Dane nie pochodzą z bazy danych. Spowoduje to utworzenie przewidywalnych, niezawodnych warunków testowych na potrzeby korzystania z dal w testach modelu strony.
Test OnGetAsync_PopulatesThePageModel_WithAListOfMessages
pokazuje, jak GetMessagesAsync
metoda jest wyśmiewany dla modelu strony:
var mockAppDbContext = new Mock<AppDbContext>(optionsBuilder.Options);
var expectedMessages = AppDbContext.GetSeedingMessages();
mockAppDbContext.Setup(
db => db.GetMessagesAsync()).Returns(Task.FromResult(expectedMessages));
var pageModel = new IndexModel(mockAppDbContext.Object);
OnGetAsync
Gdy metoda jest wykonywana w kroku Act, wywołuje metodę modelu GetMessagesAsync
strony.
Krok działania testu jednostkowego (tests/RazorPagesTestSample.Tests/UnitTests/IndexPageTests.cs
):
// Act
await pageModel.OnGetAsync();
IndexPage
metoda modelu OnGetAsync
strony (src/RazorPagesTestSample/Pages/Index.cshtml.cs
):
public async Task OnGetAsync()
{
Messages = await _db.GetMessagesAsync();
}
Metoda GetMessagesAsync
w dal nie zwraca wyniku dla tego wywołania metody. Wyśmiewany wersja metody zwraca wynik.
Assert
W kroku rzeczywiste komunikaty (actualMessages
) są przypisywane z Messages
właściwości modelu strony. Sprawdzanie typu jest również wykonywane po przypisaniu komunikatów. Oczekiwane i rzeczywiste komunikaty są porównywane przez ich Text
właściwości. Test potwierdza, że dwa List<Message>
wystąpienia zawierają te same komunikaty.
// Assert
var actualMessages = Assert.IsAssignableFrom<List<Message>>(pageModel.Messages);
Assert.Equal(
expectedMessages.OrderBy(m => m.Id).Select(m => m.Text),
actualMessages.OrderBy(m => m.Id).Select(m => m.Text));
Inne testy w tej grupie tworzą obiekty modelu strony, które obejmują DefaultHttpContext, ModelStateDictionary, an ActionContext do ustanowienia PageContext
, , ViewDataDictionary
i PageContext
. Są one przydatne podczas przeprowadzania testów. Na przykład aplikacja komunikatu ModelState
ustanawia błąd, AddModelError aby sprawdzić, czy podczas wykonywania jest zwracany OnPostAddMessageAsync
prawidłowy PageResult element:
[Fact]
public async Task OnPostAddMessageAsync_ReturnsAPageResult_WhenModelStateIsInvalid()
{
// Arrange
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase("InMemoryDb");
var mockAppDbContext = new Mock<AppDbContext>(optionsBuilder.Options);
var expectedMessages = AppDbContext.GetSeedingMessages();
mockAppDbContext.Setup(db => db.GetMessagesAsync()).Returns(Task.FromResult(expectedMessages));
var httpContext = new DefaultHttpContext();
var modelState = new ModelStateDictionary();
var actionContext = new ActionContext(httpContext, new RouteData(), new PageActionDescriptor(), modelState);
var modelMetadataProvider = new EmptyModelMetadataProvider();
var viewData = new ViewDataDictionary(modelMetadataProvider, modelState);
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>());
var pageContext = new PageContext(actionContext)
{
ViewData = viewData
};
var pageModel = new IndexModel(mockAppDbContext.Object)
{
PageContext = pageContext,
TempData = tempData,
Url = new UrlHelper(actionContext)
};
pageModel.ModelState.AddModelError("Message.Text", "The Text field is required.");
// Act
var result = await pageModel.OnPostAddMessageAsync();
// Assert
Assert.IsType<PageResult>(result);
}
Opinia o produkcie ASP.NET Core
ASP.NET Core to projekt typu open source. Wybierz link, aby przekazać opinię:
Zdarzenia
19 lis, 23 - 21 lis, 23
Dołącz do sesji online na konferencji Microsoft Ignite, aby rozwinąć swoje umiejętności i pomóc w rozwiązywaniu dzisiejszych złożonych problemów.
Zarejestruj się teraz