简体   繁体   中英

How to close down multiple browser windows after running tests in Parallel using Selenium WebDriver and NUnit C#

I am currently using the following code to shutdown my browsers after each test:

    [TearDown]
    public void StopBrowser()
    {
            if (Driver == null)
                return;
            Driver.Quit();
    }

This works fine when running single tests however when I run multiple tests in Parallel using NUnit's [Parallelizable] tag, I get my tests starting to fail due to no such session errors, Unable to connect to the remote server errors and then an Object Reference error on top so it's definitely something to do with the parallel tests.

Please find below the code that I use in the [SetUp] method:

    public IWebDriver Driver { get; set; }

    public string TestUrl;

    [SetUp]
    public void Setup()
    {
        string Browser = "Chrome";

        if (Browser == "Chrome")
        {
            ChromeOptions options = new ChromeOptions();
            options.AddArgument("--start-maximized");
            Driver = new ChromeDriver(options);
        }
        else if (Browser == "Firefox")
        {
            FirefoxDriverService service = FirefoxDriverService.CreateDefaultService();
            service.FirefoxBinaryPath = @"C:\Program Files (x86)\Mozilla Firefox\firefox.exe";
            Driver = new FirefoxDriver(service);
        }
        else if (Browser == "Edge")
        {
            EdgeDriverService service = EdgeDriverService.CreateDefaultService();
            Driver = new EdgeDriver(service);
        }

BasePage Code:

    public class BasePage<TObjectRepository> where TObjectRepository : BasePageObjectRepository
    {

        public BasePage(IWebDriver driver, TObjectRepository repository)
        {
            Driver = driver;
            ObjectRepository = repository;
        }



        public IWebDriver Driver { get; }
        internal TObjectRepository ObjectRepository { get; }
    }

BasePageObjectRepository Code:

public class BasePageObjectRepository
{
    protected readonly IWebDriver Driver;

    public BasePageObjectRepository(IWebDriver driver)
    {
        Driver = driver;
    }
}

My Tests simply call specific functions inside their relevant page and then the code inside the page simply has Selenium code that points to the elements in that Pages Object Repository ie

ObjectRepository.LoginButton.Click();

Im not sure if the way I have my tests set up is whats partially causing the issues but any help I can get in regards to this would be greatly appreciated

EDIT: Added more of my code in to help:

BaseTest Class:

    [TestFixture]
public class BaseTest
{
    public IWebDriver Driver { get; set; }

    public string TestUrl;


    [SetUp]
    public void Setup()
    {
        string Browser = "Chrome";

        if (Browser == "Chrome")
        {
            ChromeOptions options = new ChromeOptions();
            options.AddArgument("--start-maximized");
            Driver = new ChromeDriver(options);
        }
        else if (Browser == "Firefox")
        {
            FirefoxDriverService service = FirefoxDriverService.CreateDefaultService();
            service.FirefoxBinaryPath = @"C:\Program Files (x86)\Mozilla Firefox\firefox.exe";
            Driver = new FirefoxDriver(service);
        }
        else if (Browser == "Edge")
        {
            EdgeDriverService service = EdgeDriverService.CreateDefaultService();
            Driver = new EdgeDriver(service);
        }

        Driver.Manage().Window.Maximize();

        string Environment;
        Environment = "Test";



        if (Environment == "Test")
        {
            TestUrl = "https://walberton-test.azurewebsites.net/";
        }
        else if (Environment == "Live")
        {
            TestUrl = "";
        }

     }
}

[OneTimeTearDown]
public void TeardownAllBrowsers()
{
    Driver.Close();
    Driver.Quit();
}

Example of One of the Tests:

[TestFixture]
public class TimeLogsTestChrome: BaseTest
{
    [Test]
    [Parallelizable]
    [Category("Time Logs Test for Chrome")]
    public void AssertTimeLogsHeading()
    {
        Driver = new ChromeDriver();
        Driver.Manage().Window.Maximize();
        var loginPage = new LoginPage(Driver);
        var dashboard = new Dashboard(Driver);
        var timeSheets = new Timesheets(Driver);
        loginPage.GoTo("Test");
        loginPage.EnterEmailAddress("Valid");
        loginPage.EnterPassword("Valid");
        loginPage.ClickLoginButtonForLoginToDashboard();
        dashboard.ClickTimesheetsButton();
        timeSheets.AssertHeading();
        Driver.Close();
    }
}

Example of Underlying Code to the Test:

internal class Timesheets : BasePage<TimesheetsPageObjectRepository>
{

    public Timesheets(IWebDriver driver) : base(driver, new TimesheetsPageObjectRepository(driver))
    {
    }

    internal void AssertHeading()
    {
        try
        {
            Assert.AreEqual("Timesheets", ObjectRepository.TimesheetHeading);
        }
        catch (Exception ex)
        {
            throw;
        }
    }

    internal void ClickAddTimesheetButton()
    {
        ObjectRepository.AddTimesheetButton.Click();
    }

    internal void ClickSubmitTimeButton()
    {
        ObjectRepository.SubmitTimeButton.Click();
        Thread.Sleep(5000);
    }
}

Partial Example of the Page Object Repository that has most of the FindElement code:

internal class TimesheetsPageObjectRepository : BasePageObjectRepository
{

    public TimesheetsPageObjectRepository(IWebDriver driver) : base(driver) { }

    public string TimesheetHeading => Driver.FindElement(By.ClassName("pull-left")).Text;

}

NUnit tests in a fixture all share the same instance of the fixture. That's one of the fundamentals of NUnit's design that programmers have to keep in mind because it's easy for tests to step on one another's toes through use of shared state. You have to watch out for tests interfering with one another even in non-parallel situations but parallelism makes it worse.

In your case, the most likely culprit is the Driver property of the fixture. It is set by the setup of every test and whatever is held there is closed by every test . That's not what you want.

I also notice that the Driver is defined twice, once in the fixture and once in the base class. You have not posted enough code for me to understand why you are doing this, but it seems problematic.

You have to decide whether all the tests in a fixture are intended to use the same driver or not. I suspect that's not what you want, since the driver itself may have changeable state. However, you can set it up either way.

To use the same driver for all tests , make it a property of the fixture. Initialize it in a OneTimeSetUp method and release it in a OneTimeTearDown method.

To use a different driver for each test , do not make it a property. Instead, initialize a local variable in each test and release it in the test itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM