2017-11-09 11 views
0

私はSelenium Automationの新機能です。そして、私はjavaで公正な知識を持っています。ページオブジェクトモデルのオブジェクトを配列やハッシュマップで整理できますか?

ユーザー登録に使用するテストスクリプトを作成しました。

私はこれにページオブジェクトモデルを使用しました。これは私のページオブジェクトスクリプトです。

は、これは私が、私はこのように追加するのに約100個のオブジェクトを持って

public class SIgnUpTest extends PageObject { 

@FindBy(id="merchantName") 
private WebElement merchant; 

@FindBy(id="merchantCode") 
private WebElement code; 

@FindBy(id="categoryId") 
private WebElement category; 

@FindBy(id="description") 
private WebElement description; 

@FindBy(id="merchantLogo") 
private WebElement logo; 

@FindBy(id="btnNextStep1") 
private WebElement Next; 

public SIgnUpTest(WebDriver driver) { 
    super(driver); 
} 
public void enterName(String name, String code,String description){ 
    this.merchant.sendKeys(name); 
    this.code.sendKeys(code); 
    this.description.sendKeys(description); 
} 
public void Logo(String Logo){ 
    this.logo.sendKeys(Logo);  
} 
public void Next() { 
    Next.click(); 
} 

を使用しているものです。 長期使用のためにこれを整理するにはどうすればよいですか?

@Find byとWebElementを繰り返し使用する方法がありますか?

私は配列とハッシュマップを探しました。しかし、私はそれをどのように使用するか分かりません。

2次元配列またはハッシュマップを使用できますか?もしそうなら、どのように?

ありがとうございます。

私はこのようなものを使いたいです。 可能ですか?

は私が求めていることを、次のようなものを使用することができますいくつかの方法があります:コードに続いて

には問題があります。

public class SIgnUpTest extends PageObject { 
public void objects(){ 

SortedMap sm = new TreeMap(); 
sm.put("merchantName", "merchant"); 
sm.put("merchantCode", "code"); 
sm.put("categoryId", "category"); 
sm.put("description", "description"); 
sm.put("merchantLogo", "Logo"); 
sm.put("Next", "Next") 

for(int i=0; i<sm.keySet().size(); i++){ 
@FindBy(id=sm.keySet()); 
} 
for(int i=0; i<sm.keySet().size(); i++){ 
    private WebElement sm.values(); 
} 
} 
public SIgnUpTest(WebDriver driver) { 
    super(driver); 
} 
public void enterName(String name, String code,String description){ 
    this.merchant.sendKeys(name); 
    this.code.sendKeys(code); 
    this.description.sendKeys(description); 
} 
public void Logo(String Logo){ 
    this.logo.sendKeys(Logo);  
} 
public void Next() { 
    Next.click(); 
} 

} 

答えて

0

はい、これを解決する方法は複数あります。 私はあなたと対話する必要がある多くの要素を持つ大きなページを持っていると思います。 pagefactoryメソッドを使用しない方法の1つです(これはPageObjectモデルとよく混同されます)。

あなたが必要としての要素を見つけるために、ドライバのインスタンスを使用して、論理ページ上の異なるモジュールをカプセル化するために内部クラスを使用することができ driver.findElement(By.xpath("//xpath/to/element"));

かを、使用して、必要なときがあります。 は、私はあなたが最初のデザインの決定について、より明確にするため、以下のリンクを経由勧め:私の経験で

https://sqa.stackexchange.com/questions/14889/how-do-i-split-my-pageobject-model-classes https://martinfowler.com/bliki/PageObject.html

+0

私はdriver.findElementを使用している..しかし、私は中・オブジェクトの使いやすさを検討してください。私はこのパターンを使用すべきではないという意味ですか?あなたは – Sandarekha

+0

ページクラスのプライベートWebElementオブジェクトを使用することができ、その後、必要単位として、それらを上pulateします。しかし、私の電子のXPEのrienceで、線WebElementsを使用すると、ntReリファレンス例外を尊重し、スタンドアロンの電子ルの数につながることができます。代わりに WebElementsを格納する、私は方法で必要とされるときにロードされたページクラスでロケータによって保存されている、とWebElementsは法の範囲内で保存されています。 – sagarwadhwa1

0

私はのObjectMap -over-のPageObjectを好みます。

ObjectMap(PageObj複合抽象レイヤーとタクソノミー全体の学習を避けるのに役立ちます)は、--- Selenium Testing Tools Cookbook、2nd Edition --- bookおよびseleniumeasyにあります。 Composition-over-inheritanceと考えると、より柔軟でパワフルなものを選び、複雑な分類を設計する必要はありません。また、データ駆動型のアプローチもサポートしています。セレクタはコードにハードコードされていません。 PageObjはコードを複雑な抽象と結びつけるので、再利用するためにはWebサイトにこの特定のページが常に必要です。設定ファイルにはその場所がありますが、コードでパッケージ化され、ユーザが更新する予定がない場合は、設定ファイルの値をコード内で更新するのと同じように多くの手順でコードを更新します実際にカプセル化は行われません。動的フォーム(PageObj/BEM)は、テストのニーズに基づいて実行時に構築されます。複雑な分類分類はもう一度ありません。ここで

basic_contact > zip_code_contact > dealer (message+dealer info header) > quote (model+trim) > test_drive (calendar) > contact_us (email+chat) 

の例では、すぐに(holmium.core様およびpage-objects)のPOMに飛び込む前に、いくつかの考慮事項を以下のとおりです。

  1. 自動的に構築されたページオブジェクトを維持すると使いにくいです。ヘッダーやフッター、または特定されたウィジェットに要素をグループ化していない場合、大きなリストがあります。自動的に生成された名前は、その内容を説明するだけの十分な読み込みをしますか?

  2. デザインが制限される場合があります。あなたはより良い抽象を無視するために凝視します。

  3. 特に、リファクタリング(構造と実装の両方)には、十分な柔軟性がありません。

more at dzoneを検索してください。 Javaの実装hereおよびhere

0

これを行うには、カスタム注釈、elementfactoryおよびデコレータを作成する必要があります。以下のコードで適切なインポートを追加します。

注釈

@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.FIELD}) 
public @interface MultipleFind { 

    String delimiter() default "@@"; 
    String[] elementDetails(); 
} 

サンプルのPageObjectからusernameInput @@ ID @@ユーザ名からを地図でキーとして使用されます最初の部分。 second partロケーター戦略であり、これはHow.java enumの値に対応します。 第3部分は、ロケータです。このページオブジェクトには、FindByなどの標準アノテーションとカスタムアノテーションを含めることができます。

public class LoginPageObject extends BasePageObject<LoginPageObject> { 

    //Conventional declaration 
    @FindBy(how=How.ID, using="username") 
    private WebElement usernameInput; 

    //Conventional declaration 
    @FindBy(how=How.NAME, using="pwd") 
    private WebElement passwordInput; 

    //Custom multiple annotation 
    @MultipleFind(elementDetails = { "[email protected]@[email protected]@username", "[email protected]@[email protected]@pwd" }) 
    private Map<String, WebElement> loginui;   

    public LoginMapPageObject(WebDriver driver) {   
     super(driver); 

     //PageFactory initialization with custom factory and decorator 
     MapElementLocatorFactory melf = new MapElementLocatorFactory(driver); 
     MapFieldDecorator mfd = new MapFieldDecorator(melf); 
     PageFactory.initElements(mfd, this); 
    } 

    private void enterAndSubmitLoginDetails() {   
     //Conventional calls 
     //usernameInput.sendKeys("user"); 
     //passwordInput.sendKeys("password"); 

     //Call to retrieve element from map 
     loginui.get("usernameInput").sendKeys("user"); 
     loginui.get("passwordInput").sendKeys("password"); 
    }  
} 

MapAnnotations -

public class MapAnnotations extends Annotations { 
    public MapAnnotations(Field field) { 
     super(field); 
    } 

    public By buildBy() { 
     if (getField().getAnnotation(MultipleFind.class) != null) 
      return null; 
     return super.buildBy(); 
    } 

    public Map<String, By> buildMapBys() { 
     Map<String, By> details = null; 
     Optional<Annotation> annot = Arrays.asList(getField().getAnnotations()) 
       .stream() 
       .filter(a -> a.annotationType().equals(MultipleFind.class)) 
       .findAny(); 
     if(annot.isPresent()) { 
      details = createLocatorDetails(annot.get()); 
     } 
     return details; 
    } 

    private Map<String, By> createLocatorDetails(Annotation annot) { 
     String[] elemDets = ((MultipleFind) annot).elementDetails(); 
     String delim = ((MultipleFind) annot).delimiter(); 
     Map<String, By> details = Arrays.stream(elemDets) 
       .map(d -> d.split(delim)) 
       .collect(Collectors.toMap(a -> a[0], a -> createBy(a[1], a[2]))); 
     return details; 
    } 

    private By createBy(String howStr, String using) { 
     How how = How.valueOf(howStr); 
     switch (how) { 
      case CLASS_NAME: 
      return By.className(using); 
      case CSS: 
      return By.cssSelector(using); 
      case ID: 
      case UNSET: 
      return By.id(using); 
      case ID_OR_NAME: 
      return new ByIdOrName(using); 
      case LINK_TEXT: 
      return By.linkText(using); 
      case NAME: 
      return By.name(using); 
      case PARTIAL_LINK_TEXT: 
      return By.partialLinkText(using); 
      case TAG_NAME: 
      return By.tagName(using); 
      case XPATH: 
      return By.xpath(using); 
      default: 
      // Note that this shouldn't happen (eg, the above matches all 
      // possible values for the How enum) 
      throw new IllegalArgumentException("Cannot determine how to locate element "); 
     } 
    } 

    protected void assertValidAnnotations() { 
     FindBys findBys = getField().getAnnotation(FindBys.class); 
     FindAll findAll = getField().getAnnotation(FindAll.class); 
     FindBy findBy = getField().getAnnotation(FindBy.class); 
     MultipleFind multFind = getField().getAnnotation(MultipleFind.class); 
     if (multFind != null 
       && (findBys != null || findAll != null || findBy != null)) { 
      throw new IllegalArgumentException(
        "If you use a '@MultipleFind' annotation, " 
          + "you must not also use a '@FindBy' or '@FindBys' or '@FindAll' annotation"); 
     } 
     super.assertValidAnnotations(); 
    } 
} 

MapElementLocatorFactory

public class MapElementLocatorFactory implements ElementLocatorFactory { 

    private final SearchContext searchContext; 

     public MapElementLocatorFactory(SearchContext searchContext) { 
     this.searchContext = searchContext; 
     } 

     public MapElementLocator createLocator(Field field) { 
     return new MapElementLocator(searchContext, field); 
     } 
} 

MapElementLocator

public class MapElementLocator extends DefaultElementLocator { 

    private Map<String, By> elementBys; 
    private SearchContext searchContext; 

    public MapElementLocator(SearchContext searchContext, Field field) { 
     this(searchContext, new MapAnnotations(field)); 
    } 

    public MapElementLocator(SearchContext searchContext,MapAnnotations annotations) { 
     super(searchContext, annotations); 
     this.elementBys = annotations.buildMapBys(); 
     this.searchContext = searchContext; 
    } 

    public WebElement findElement(String elementName) { 
     By by = elementBys.get(elementName); 
     return searchContext.findElement(by); 
    } 
} 

MapFieldDecorator

public class MapFieldDecorator extends DefaultFieldDecorator { 

    public MapFieldDecorator(ElementLocatorFactory factory) { 
     super(factory); 
    } 

    public Object decorate(ClassLoader loader, Field field) { 
     if (Map.class.isAssignableFrom(field.getType())) {   
      MapElementLocator locator = (MapElementLocator) factory.createLocator(field);   
      return proxyForMapLocator(loader, locator); 
     } 
     return super.decorate(loader, field); 
    } 

    @SuppressWarnings("unchecked") 
    protected Map<String, WebElement> proxyForMapLocator(ClassLoader loader, 
      MapElementLocator locator) { 
     InvocationHandler handler = new LocatingMapElementHandler(locator); 
     Map<String, WebElement> proxy; 
     proxy = (Map<String, WebElement>) Proxy.newProxyInstance(loader, 
       new Class[] { Map.class }, handler); 
     return proxy; 
    } 
} 

LocatingMapElementHandler

public class LocatingMapElementHandler implements InvocationHandler { 
    private final MapElementLocator locator; 

    public LocatingMapElementHandler(MapElementLocator locator) { 
     this.locator = locator; 
    } 

    public Object invoke(Object object, Method method, Object[] objects) throws Throwable { 
     if(method.getName() != "get") 
      throw new UnsupportedOperationException("Only get method of Map is supported for this proxy.");  
     return locator.findElement((String)objects[0]); 
    } 
} 

これはリストだけではない、個々のWebElementで動作します。あなたはそれを実装しようとすることができますが、問題は、単一または複数の要素が必要な場合に正しく判断することが不可能な一般的な情報を消去することです。 Mapプロキシでget()メソッドだけが動作し、他のものはUnsupportedExceptionをスローします。

関連する問題