Кто-нибудь знает, почему я иногда получаю исключение, когда использую Selenium вместе с Testcontainers. См. ниже:
Произошло исключение: CLR/OpenQA.Selenium.WebDriverException Исключение типа «OpenQA.Selenium.WebDriverException» возникло в WebDriver.dll, но не было обработано в коде пользователя: «Обнаружено неизвестное исключение при отправке HTTP-запроса на удаленный сервер WebDriver для URL-адреса http://localhost:4444/session . Сообщение об исключении: «Произошла ошибка при отправке запроса». Найдены внутренние исключения, подробнее см. $exception в окне переменных. Самое внутреннее исключение System.IO.IOException : ответ завершился преждевременно. в System.Net.Http.HttpConnection.d__61.MoveNext()
Это происходит в половине случаев, когда я запускаю следующий конструктор тестов (C#/xUnit.net):
public DockerShould()
{
var gridNetwork = new NetworkBuilder()
.WithName("gridNetwork")
.Build();
const int SessionPort = 4444;
var containerHub = new ContainerBuilder()
.WithImage("selenium/hub:4.8")
.WithName("selenium-hub")
.WithPortBinding(4442, 4442)
.WithPortBinding(4443, 4443)
.WithPortBinding(SessionPort, SessionPort)
.WithNetwork(gridNetwork)
.Build();
var firefoxEnvironment = new Dictionary<string, string>()
{
{"SE_EVENT_BUS_HOST", "selenium-hub"},
{"SE_EVENT_BUS_PUBLISH_PORT", "4442"},
{"SE_EVENT_BUS_SUBSCRIBE_PORT", "4443"}
};
var containerFirefox = new ContainerBuilder()
.WithImage("selenium/node-firefox:4.8")
.WithEnvironment(firefoxEnvironment)
.WithNetwork(gridNetwork)
.Build();
var firefoxVideoEnvironment = new Dictionary<string, string>()
{
{"DISPLAY_CONTAINER_NAME", "firefox"},
{"FILE_NAME", "firefox.mp4"}
};
var containerFirefoxVideo = new ContainerBuilder()
.WithImage("selenium/video:ffmpeg-4.3.1-20230210")
.WithNetwork(gridNetwork)
.WithEnvironment(firefoxVideoEnvironment)
// .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(SessionPort))
.Build();
gridNetwork.CreateAsync().Wait();
containerHub.StartAsync().Wait();
containerFirefox.StartAsync().Wait();
containerFirefoxVideo.StartAsync().Wait();
Thread.Sleep(5000);
_remoteWebDriver = new RemoteWebDriver(new Uri("http://localhost:4444"), new FirefoxOptions());
}
Исключение возникает при создании нового RemoteWebDriver. Я добавил thread.sleep, чтобы дать небольшую задержку перед созданием переменной. Я не уверен, что это действительно помогает. Есть ли более элегантный способ убедиться, что все контейнеры запущены, прежде чем пытаться создать веб-драйвер (что, как я предполагаю, является проблемой)?
В вашей конфигурации есть несколько недостатков. Я не уверен, какой из них в конечном итоге вызывает проблему, но ниже я привел рабочий пример. Ключевые части были прокомментированы. Обратите внимание, что в примере не используется стратегия ожидания для определения готовности контейнера или службы внутри него. Это аспект, который вам все еще нужно будет решить. Но сначала давайте взглянем на некоторые основы.
WithPortBinding(4444, 4444)
. Чтобы предотвратить конфликты портов, назначьте случайный порт хоста с помощью WithPortBinding(4444, true)
и извлеките его из экземпляра контейнера с помощью GetMappedPublicPort(4444)
.WithNetworkAliases(string)
.localhost
для доступа к службам, работающим внутри контейнеров. Конечная точка зависит от среды Docker. Вместо этого используйте свойство Hostname
.public sealed class StackOverflow : IAsyncLifetime
{
private const ushort WebDriverPort = 4444;
private readonly INetwork _network;
private readonly IContainer _selenium;
private readonly IContainer _firefox;
private readonly IContainer _ffmpg;
public StackOverflow()
{
_network = new NetworkBuilder()
.Build();
_selenium = new ContainerBuilder()
.WithImage("selenium/hub:4.8")
// Use random assigned host ports to access the service running inside the containers.
.WithPortBinding(WebDriverPort, true)
.WithNetwork(_network)
// Use a network-alias to communication between containers.
.WithNetworkAliases(nameof(_selenium))
.Build();
_firefox = new ContainerBuilder()
.WithImage("selenium/node-firefox:4.8")
.WithEnvironment("SE_EVENT_BUS_HOST", nameof(_selenium))
.WithEnvironment("SE_EVENT_BUS_PUBLISH_PORT", "4442")
.WithEnvironment("SE_EVENT_BUS_SUBSCRIBE_PORT", "4443")
.WithNetwork(_network)
.WithNetworkAliases(nameof(_firefox))
.Build();
_ffmpg = new ContainerBuilder()
.WithImage("selenium/video:ffmpeg-4.3.1-20230210")
.WithEnvironment("DISPLAY_CONTAINER_NAME", nameof(_firefox))
.WithEnvironment("FILE_NAME", nameof(_firefox) + ".mp4")
.WithNetwork(_network)
.WithNetworkAliases(nameof(_ffmpg))
.Build();
}
public async Task InitializeAsync()
{
await _network.CreateAsync()
.ConfigureAwait(false);
// You can await Task.WhenAll(params Task[]) too.
await _selenium.StartAsync()
.ConfigureAwait(false);
await _firefox.StartAsync()
.ConfigureAwait(false);
await _ffmpg.StartAsync()
.ConfigureAwait(false);
}
public async Task DisposeAsync()
{
await _selenium.DisposeAsync()
.ConfigureAwait(false);
await _firefox.DisposeAsync()
.ConfigureAwait(false);
await _ffmpg.DisposeAsync()
.ConfigureAwait(false);
await _network.DeleteAsync()
.ConfigureAwait(false);
}
[Fact]
public async Task Question()
{
// TODO: The container configurations mentioned above lack a wait strategy. It is crucial that you add a wait strategy to each of them to determine readiness (afterwards remove this line).
await Task.Delay(TimeSpan.FromSeconds(15))
.ConfigureAwait(false);
// Use the Hostname property instead of localhost. Get the random assigned host port with GetMappedPublicPort(ushort).
var webDriver = new RemoteWebDriver(new UriBuilder(Uri.UriSchemeHttp, _selenium.Hostname, _selenium.GetMappedPublicPort(WebDriverPort)).Uri, new FirefoxOptions());
Assert.NotNull(webDriver.SessionId);
}
}
Я хотел бы спросить вас, пожалуйста: что вы используете в режиме селена хаба и узла? Я рекомендовал использовать в этом случае автономный режим — и почему? Потому что тесткоанинер webDriver на мой взгляд работает как динамическая сетка в s:docker-selenium github Я также спрашиваю, потому что я просто работаю над этим: Feature-контейнер WebDriver Поэтому я хотел бы узнать ваше мнение и узнать, как я могу сопоставить возможности testcotanienr и RemoteWebDriver.
Как сейчас написано, ваш ответ неясен. Пожалуйста, отредактируйте , чтобы добавить дополнительные сведения, которые помогут другим понять, как это отвечает на заданный вопрос. Вы можете найти больше информации о том, как писать хорошие ответы в справочном центре.