Selenide: Run test parallel with Guice, TestNg and Selenide

Created on 6 Nov 2017  路  3Comments  路  Source: selenide/selenide

The problem

We want to run our tests parallel, we use Guice, TestNg, and Seledine.
The problem is when we add in testng.xml parameter

parallel="tests" thread-count="2"

First, opens first browser, does login, then opens another browser with no page opened. Then it throws error like

com.codeborne.selenide.ex.ElementNotFound: Element not found {By.xpath: //div[@id='toast-container']}

So, as we guess, problem is that Guice @Injection doesn't know which browser to use exactly.

Details

Here's how we use Guice:

We have NavigationModule where we just bind Navigation service to Singleton

public class NavigationModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(NavigationService.class).in(Singleton.class);
    }
}

After that we use Navigation service to do some navigation on the page.

public class NavigationService {

    @Inject
    private LoginPage loginPage;
    @Inject
    private TemplateManagementPage templateManagementPage;
    @Inject
    private CreateTemplatePage createTemplatePage;
    @Inject
    private NavigationMenu navigationMenu;

    public TemplateManagementPage logIn(String username, String password) {
        return loginPage.login(username, password);
    }

    public TemplateManagementPage openTemplateManagementPage() {
        navigationMenu.openMenu()
                .openTemplatesMenu()
                .openTemplateManagementPage();
        return templateManagementPage;
    }
}

In BaseTest we do login and inject NavigationService

   @Guice(modules = NavigationModule.class)
   public abstract class BaseTest{

    @Inject
    protected NavigationService navigationService;

    protected TemplateManagementPage templateManagementPage;

    @BeforeSuite
    public void login() {
        User user = UserFactory.getDefaultUser();
        templateManagementPage = navigationService.logIn(user.getUserName(), user.getPassword());
    }
}

And the last thing we open one page before each test method

    @BeforeMethod(description = "Open create template page")
    public void openCreateTemplatePage() {
        templatePage = navigationService.openCreateTemplatePage();
    }
  • What we want to try is create for each singleton different instance of browser in different threads and tell it to use
  • Is there any way to do that? We guess we could use WebDriverRunner to manage WebDriver instances, but we no sure how to

Tell us about your environment

  • Selenide Version: 4.8
question

Most helpful comment

@danteg233 So, can we close the issue?

P.S. I would say that you have over-engineered your tests. I don't see any reason to use dependency injection/Guice. It brings complexity but doesn't solve any real problems. And look, you still have public static method UserFactory.getDefaultUser() - meaning that the whole dependency injection doesn't make sense anymore.

The problem described in the current issue could not exist if you simplify tests and throw DI away. :)

All 3 comments

Hi there. After few weeks, we finally found the reason of this issue.
The problem was in fields initialization.
Here, in BaseTest was problem

@Guice(modules = NavigationModule.class)
   public abstract class BaseTest{

    @Inject
    protected NavigationService navigationService;

    protected TemplateManagementPage templateManagementPage;

    @BeforeSuite
    public void login() {
        User user = UserFactory.getDefaultUser();
        templateManagementPage = navigationService.logIn(user.getUserName(), user.getPassword());
    }
}

With field

protected TemplateManagementPage templateManagementPage;

In out project, all pages extends Page class

public abstract class Page{

    public Page() {
        page(this);
    }
}

So, as u can see it just does initialization. And here's the problem, when we do initialization of TemplateManagementPage in BaseTest through field, Page constructor calls Selenide page method and that methods creates an instance of browser, and when we wanna do login, it again creates another instance of browser, so basically that's all. All what u need it's to remove

protected TemplateManagementPage templateManagementPage;

and change @BeforeSuite to @BeforeTest

So the final solution looks like

@Guice(modules = NavigationModule.class)
public abstract class BaseTest{

    @Inject
    protected NavigationService navigationService;

    @BeforeTest()
    public void login(){
        User user = UserFactory.getDefaultUser();
        navigationService.logIn(user.getUserName(), user.getPassword());
    }
}

So now all tests runs in parallel, as we wanted.

@danteg233 So, can we close the issue?

P.S. I would say that you have over-engineered your tests. I don't see any reason to use dependency injection/Guice. It brings complexity but doesn't solve any real problems. And look, you still have public static method UserFactory.getDefaultUser() - meaning that the whole dependency injection doesn't make sense anymore.

The problem described in the current issue could not exist if you simplify tests and throw DI away. :)

@danteg233 I know you solved this issue, but I'm running into the same thing, and your solution isn't working for me. Is there anyway you could post a full working solution (even sanitized)? Your snippets weren't enough for me to solve the problem

Was this page helpful?
0 / 5 - 0 ratings