Что такое Playwright?
Playwright – это фреймворк для тестирования веб-интерфейса от компании Microsoft, в котором можно работать с различными языками. Playwright поддерживает JavaScript/TypeScript, Python, Java и, конечно же, C#. В нем также есть поддержка консольного браузера в различных браузерах. Он используется с фреймворками для модульного тестирования, и поэтому его можно запустить в рамках конвейера CI/CD. Синтаксис интуитивно понятен, и мне он очень нравится. Кроме того, документация очень хороша и помогает легко начать с ним работу.
В этой статье я не буду знакомить вас с Playwright. На самом деле, веб-сайт и документация – гораздо лучший ресурс для знакомства. Я бы хотел поиграться с ним и использовать его по-другому. Вместо того чтобы тестировать уже загруженное на хост веб-приложение, я бы хотел тестировать веб-приложение, которое размещается в тестовом проекте с помощью фабрики WebApplicationFactory
. Таким образом, вы получите действительно изолированные UI-тесты, которые не связаны с другой инфраструктурой и не упадут из-за проблем с сетью.
Работает ли это?
БЕСПЛАТНО СКАЧАТЬ КНИГИ в телеграм канале "Библиотека тестировщика"
Давайте попробуем:
Настройка решения
Следующие строки создают проект ASP.NET Core MVC и проект тестов NUnit. После этого будет создан файл решения, и проекты будут добавлены в него. Последняя команда добавляет реализацию NUnit Playwright в тестовый проект:
dotnet new mvc -n PlayWithPlaywright dotnet new nunit -n PlayWithPlaywright.Tests dotnet new sln -n PLayWithPlaywright dotnet sln add .\PlayWithPlaywright\ dotnet sln add .\PlayWithPlaywright.Tests\ dotnet add .\PlayWithPlaywright.Tests\ package Microsoft.Playwright.NUnit
Выполните эти команды и сбилдите решение:
dotnet build
Билд нужен для копирования скрипта PowerShell в выходной каталог тестового проекта. Этот скрипт PowerShell — интерфейс командной строки для управления Playwright.
Далее нам нужно установить необходимые браузеры для выполнения тестов через PowerShell:
.\PlayWithPlaywright.Tests\bin\Debug\net7.0\playwright.ps1 install
Генерация тестового кода
Использование команды codegen
помогает автогенерировать тестовый код, который можно скопировать в тестовый проект:
.\PlayWithPlaywright.Tests\bin\Debug\net7.0\playwright.ps1 codegen https://asp.net-hacker.rocks/
Эта команда открывает инспектор Playwright, в котором вы можете записать тестовый сценарий. Во время перехода по приложению справа будет сгенерирован тестовый код:
Вместо того чтобы тестировать внешний сайт, как это делал я, вы можете вызвать codegen
на локально запущенном приложении.
Просто скопируйте сгенерированный код в тестовый проект NUnit и исправьте пространство имен и имя класса так, чтобы они соответствовали пространству имен вашего проекта.
Используя сгенерированный код в качестве примера, вы сможете написать больше тестов вручную.
Если это сделано, запустите dotnet test
, чтобы выполнить сгенерированный тест и убедиться, что Playwright работает.
Начинаем играться
Обычно Playwright тестирует приложения, запущенные на сервере. При этом возникает одна простая проблема: если тест не может подключиться к запущенному приложению из-за проблем с сетью, о упадет. Как правило, тест должен иметь только одну единственную причину для “фейла”: он упадет, если не работает в соответствии с ожидаемым результатом.
Решением может стать тестирование веб-приложения, размещенного на той же инфраструктуре и в рамках того же процесса, что и реальное тестирование.
Microsoft уже предоставила возможность написать интеграционные тесты для веб-приложения с помощью WebApplicationFactory. Моя идея заключалась в том, чтобы использовать эту WebApplicationFactory
для хостинга приложения, которое можно тестировать с помощью Playwright.
Поскольку WebApplicationFactory также предоставляет HttpClient, я ожидал бы получить URL для подключения. Этот HttpClient будет иметь BaseAddress, который я могу использовать для передачи в Playwright.
Действительно ли это сработает?
WebApplicationFactory и Playwright
На самом деле, мы не можем объединить их по умолчанию, потому что WebApplicationFactory
на самом деле не “хостит” веб-приложение по HTTP. Это означает, что здесь не используется Kestrel для выставления конечной точки по HTTP. WebApplicationFactory
создает тестовый сервер, который размещает приложение в памяти и просто имитирует настоящий HTTP-сервер.
Нам нужно найти способ запустить HTTP-сервер, например, как Kestrel, чтобы разместить приложение. На самом деле мы могли бы запустить WebApplicationBuilder
, но идея заключалась в том, чтобы повторно использовать конфигурацию Program.cs приложения, которое мы хотим протестировать. Как это делается с помощью WebApplicationFactory
.
Дэниел Донбаванд действительно нашел решение как переопределить WebApplicationFactory для реального размещения приложения по HTTP и получить конечную точку, которая может быть использована с Playwright. Я использовал решение Дэниелса, но сделал его более универсальным.
Давайте посмотрим, как это работает вместе с Playwright.
Сначала добавьте ссылку на веб-проект в тестовом проекте Playwright и добавьте ссылку на пакет в Microsoft.AspNetCore.Mvc.Testing.
dotnet add .\PlayWithPlaywright.Tests\ reference .\PlayWithPlaywright\ dotnet add .\PlayWithPlaywright.Tests\ package Microsoft.AspNetCore.Mvc.Testing
Первый необходим для использования Program.cs
с WebApplicationFactory
. Второй добавляет WebApplicationFactory
и тестовый сервер в тестовый проект.
Чтобы использовать класс Program
, определенный в Program.cs
, который использует минимальный API, вы можете добавить пустой частичный класс Program в Program.cs
.
Я просто поместил следующую строку в конец Program.cs
:
public partial class Program { }
Чтобы сделать тесты Playwright как можно более универсальными, я создал абстрактный класс SelfHostedPageTest
, который наследует класс PageTest
, поставляемый с Playwright, и использовал там CustomWebApplicationFactory
, а также выставил адрес сервера для тестового класса, который наследует SelfHostedPageTest
:
public abstract class SelfHostedPageTest<TEntryPoint> : PageTest where TEntryPoint : class { private readonly CustomWebApplicationFactory<TEntryPoint> _webApplicationFactory; public SelfHostedPageTest(Action<IServiceCollection> configureServices) { _webApplicationFactory = new CustomWebApplicationFactory<TEntryPoint>(configureServices); } protected string GetServerAddress() => _webApplicationFactory.ServerAddress; }
Фактический тест Playwright просто наследует SelfHostedPageTest
вместо PageTest
следующим образом:
public class PlayWithPlaywrightHomeTests : SelfHostedPageTest<Program> { public PlayWithPlaywrightHomeTests() : base(services => { // configure needed services, like mocked db access, fake mail service, etc. }) { } // ... }
Как вы видите, я передаю тип Program в качестве универсального аргумента в SelfHostedPageTest
. CustomWebApplicationFactory
, которая используется внутри, – это почти та же реализация, что и у Даниэля. Я только добавил универсальный аргумент для класса Program, а также добавил возможность передавать конфигурацию сервиса через конструктор:
internal class CustomWebApplicationFactory<TEntryPoint> : WebApplicationFactory<TEntryPoint> where TEntryPoint : class { private readonly Action<IServiceCollection> _configureServices; private readonly string _environment; public CustomWebApplicationFactory( Action<IServiceCollection> configureServices, string environment = "Development") { _configureServices = configureServices; _environment = environment; } protected override void ConfigureWebHost(IWebHostBuilder builder) { builder.UseEnvironment(_environment); base.ConfigureWebHost(builder); // Add mock/test services to the builder here if(_configureServices is not null) { builder.ConfigureServices(_configureServices); } } // ... }
Теперь мы можем использовать GetServerAddress()
для получения адреса сервера и передачи его в метод Page.GotoAsync()
:
[Test] public async Task TestWithWebApplicationFactory() { var serverAddress = GetServerAddress(); await Page.GotoAsync(serverAddress); await Expect(Page).ToHaveTitleAsync(new Regex("Home Page - PlayWithPlaywright")); Assert.Pass(); }
Вот и все.
Чтобы опробовать его, достаточно вызвать dotnet test в командной строке или PowerShell или запустить соответствующий тест в обозревателе тестов.
Заключение
Результат в моем тестовом проекте выглядит следующим образом: все тесты были запущены, когда я находился оффлайн:
Один “зафейленый” тест – это записанная тестовая сессия моего блога на https://asp.net-hacker.rocks/ а другой – демо-тест, который я нашел на https://playwright.dev. Пройденный тест – это тот, который использует CustomWebApplicationFactory
.
Именно такого результата я и ожидал.
Пример вы найдете в моем репозитории GitHub.
Если вы нашли какую-либо ошибку в этом посте, не стесняйтесь сообщить мне об этом: сообщите о проблеме на GitHub или отредактируйте эту страницу на GitHub и отправьте мне PullRequest.
Перевод статьи «Play with Playwright».