如何更改WebDriver的语言?

20
我想在不同的语言中执行我的Selenium测试。是否可以在运行时更改现有WebDriver的语言,还是必须重新创建浏览器实例?
目前我只使用Firefox,但我希望在以后测试不同的浏览器。
在Firefox中,我是这样设置语言的:
FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("intl.accept_languages", "de");
WebDriver driver = new FirefoxDriver(profile);

我还实现了一个WebDriverPool,它持有一个WebDriver实例,以便可以在测试之间共享。如果语言只能在创建时设置,那么我可以为每个区域设置一个实例。

总的来说,我想知道我是否忽略了什么。为什么改变语言如此困难?难道不应该有一个像WebDriver.setAcceptLanguages(Locale)这样的方法吗?

简而言之,我的问题是:

  1. 为什么没有WebDriver.setAcceptLanguages(Locale)
  2. 如何更改不同WebDrivers的语言?
  3. 我能在运行时更改语言吗?
  4. 你们是如何实现自己的WebDriverPool的?或者你们是每次都重新创建它们的吗?

2
我可以想到几种情况:检查不同语言环境下的日期和数字格式以及输入,用不同的语言截屏,如果有人使用不支持的语言,可能会显示一些提示等等。我认为,如果您的 Web 应用程序支持多种语言,则在多个语言中进行测试对于某些测试用例是有意义的,对吧? - Tim Büthe
3个回答

14

最终我创建了一个WebDriverPool,为每个WebDriver类型(例如FirefoxDriver.class)和区域设置(例如en_US)的组合创建一个实例。也许这对某些人有用。

public class WebDriverPool {

  private Map<String, WebDriver> drivers = new HashMap<String, WebDriver>();
  private List<WebDriver> driversInUse = new ArrayList<WebDriver>();

  public WebDriverPool() {
    Runtime.getRuntime().addShutdownHook(new Thread(){
      @Override
      public void run(){
        for (WebDriver driver : drivers.values())
          driver.close();

        if (!driversInUse.isEmpty())
          throw new IllegalStateException("There are still drivers in use, did someone forget to return it? (size: " + driversInUse.size() + ")");
      }
    });
  }

  private WebDriver createFirefoxDriver(Locale locale){
    FirefoxProfile profile = new FirefoxProfile();
    profile.setPreference("intl.accept_languages", formatLocale(locale));
    return new FirefoxDriver(profile);
  }

  private String formatLocale(Locale locale) {
    return locale.getCountry().length() == 0
      ? locale.getLanguage()
      : locale.getLanguage() + "-" + locale.getCountry().toLowerCase();
  }

  /**
   * @param clazz
   * @param locale
   * @return web driver which can be new or recycled
   */
  public synchronized WebDriver getWebDriver(Class<? extends WebDriver> clazz, Locale locale){

    String key = clazz.getName() + "-" + locale;

    if(!drivers.containsKey(key)){

      if(clazz == FirefoxDriver.class){
        drivers.put(key, createFirefoxDriver(locale));
      }

      // TODO create other drivers here ...

      // else if(clazz == ChromeDriver.class){
      //     drivers.put(key, createChromeDriver(locale));
      // }

      else{
        throw new IllegalArgumentException(clazz.getName() + " not supported yet!");
      }
    }

    WebDriver driver = drivers.get(key);

    if(driversInUse.contains(driver))
      throw new IllegalStateException("This driver is already in use. Did someone forgot to return it?");

    driversInUse.add(driver);
    return driver;
  }

  public synchronized void returnWebDriver(WebDriver driver){
    driversInUse.remove(driver);
  }
}

我喜欢那个类,但我不明白为什么要评估使用了哪个WebDriver... 可以请您解释一下吗? - Franz Ebner
@Frank:你的问题是,为什么Class<> clazz是“getWebDriver”方法的参数?这是因为调用测试类可以决定应该创建什么样的驱动程序。我们需要这个,因为只有InternetExplorer的测试需要使用ActiveX。 - Tim Büthe
不,我不明白为什么要记录是否正在使用驱动程序(private List<WebDriver> driversInUse)...那只是为了正确关闭它们吗? - Franz Ebner
1
是的,这只是为了帮助开发人员正确关闭所有浏览器。 - Tim Büthe
因此,使用相同设置进行多线程测试是不正确的吗?! - Franz Ebner
显示剩余5条评论

5
你也可以通过Firefox的about:config来实现。但你需要使用Actions来操纵它。
以下是一段Java代码。
    Actions act = new Actions(webDriver);          

    webDriver.get("about:config");

    // warning screen
    act.sendKeys(Keys.RETURN).perform();

    // Go directly to the list, don't use the search option, it's not fast enough
    act.sendKeys(Keys.TAB).perform();

    // Go to the intl.accept_languages option
    act.sendKeys("intl.accept_languages").sendKeys(Keys.RETURN).perform();

    // fill the alert with your parameters
    webDriver.switchTo().alert().sendKeys("fr, fr-fr, en-us, en");
    webDriver.switchTo().alert().accept();

在使用webDriver3时,执行act.sendKeys(Keys.RETURN).perform();后出现了UnreachableBrowserException异常。 - LanMan
@LanMan,对于webDriver3我没有问题,但是about:config的接口已经改变了。根据Firefox版本,必须重写操作。 - Cedric

-1

我担心WebDriver的整个理念就是像浏览器一样运作 - 所以您可以更改浏览器的语言,但必须更改操作系统中的区域设置,或者希望应用程序为您完成。

例如 - 德国数字格式使用逗号分隔小数,而英文数字使用点号。如果您想测试数字格式在英文环境和德文环境下的行为,只能通过以下两种方法之一进行:

  1. 将操作系统区域设置从德文更改为英文或反之亦然
  2. 更改浏览器语言并希望应用程序更改行为。

回答您的问题:

  1. Webdriver 没有 setLocale,因为 WebDriver 模拟的是浏览器而非操作系统。
  2. 我会这样做(Java 代码):

    private WebDriver driver;  
    
    public enum Language {en-us, de}
    
    public WebDriver getDriver(Language lang){
      String locale = lang.toString();
      FirefoxProfile profile = new FirefoxProfile();
      profile.setPreference("intl.accept_languages", locale);
      driver = new FirefoxDriver(profile);   
      return driver;       
    }
    
    @Test
    public void TestNumber(){
      WebDriver drv = getDriver(Language.en);
      drv.get("http://the-site.com");
      WebElement el = drv.findElement //... find element
      String number = el.getText();
      Assert.assertEquals(number, "123.45");
      drv.close();
      drv = getDriver(Language.de);
      drv.get("http://the-site.com");
      WebElement el = drv.findElement //... find element
      String number = el.getText();
      Assert.assertEquals(number, "123,45");
      drv.close();
    }
    
  3. 恐怕您需要关闭浏览器,然后再以不同的语言重新打开它。

  4. 我个人为每个测试创建一个新的浏览器实例。

顺便提一下,上面的代码片段假设Web应用程序根据浏览器语言更改向用户显示数字的方式。


1
感谢您的回答,但很遗憾这并没有对我有太大帮助。您说区域设置只能在操作系统级别更改,这是不正确的。您可以在运行Firefox或Chrome时更改区域设置,并且在下一次请求时,“accept_languages”在http标头中也会更改。我们的应用程序使用此语言来选择文本并格式化数字和日期。 - Tim Büthe
其次,每次重新创建浏览器实例都非常缓慢。您应该考虑实现一个池来解决这个问题。 - Tim Büthe
1
要影响Chrome、Firefox和Internet Explorer中的Accept-Language标头的值,只需更改浏览器内部的语言设置并重新加载页面,而无需修改任何操作系统设置。 - martin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接