Использование @property и @ attribute.setter помогает не только использовать «pythonic» способ, но также проверять правильность атрибутов при создании объекта и при его изменении.
class Person(object):
def __init__(self, p_name=None):
self.name = p_name
@property
def name(self):
return self._name
@name.setter
def name(self, new_name):
if type(new_name) == str: #type checking for name property
self._name = new_name
else:
raise Exception("Invalid value for name")
Таким образом, вы фактически скрываете атрибут _name от разработчиков-клиентов, а также выполняете проверки типа свойства имени. Обратите внимание, что, следуя этому подходу даже во время инициализации, вызывающий сеттер. Итак:
p = Person(12)
приведет к:
Exception: Invalid value for name
Но:
>>>p = person('Mike')
>>>print(p.name)
Mike
>>>p.name = 'George'
>>>print(p.name)
George
>>>p.name = 2.3 # Causes an exception
Вы можете использовать команду getXpathCount, чтобы определить количество совпадающих элементов. Затем вы можете прокручивать их, используя приращение, чтобы найти каждый элемент индивидуально. В следующем примере Java (TestNG / JUnit) проверяется, установлены ли все флажки на странице:
int totalCheckboxes = session().getXpathCount("//input[@type='checkbox']").intValue();
for (int i = 1; i < totalCheckboxes+1; i++) {
assertTrue(session().isChecked("//input[@type='checkbox'][" + i + "]"));
}
Selenium не может оценить список элементов, возвращаемых локатором. Он просто берет первый и делает с ним все.
Ответ Дэйва - лучшая альтернатива тому, что вы ищете.
Я пытаюсь сделать то же самое в Selenium и попробовал использовать пример @dave-hunt 'а, но это неправильный метод для поиска отдельного элемента в коллекции.
Рассмотрим следующий пример:
<form>
<div>
<input type="text" name="field1" />
</div>
<div>
<input type="text" name="field2" />
</div>
</form>
Если вы используете выражение типа:
//input[@type='text'][1]
это вернет все текстовые входы на странице. Почему? Потому что каждый ввод является первым совпадающим элементом в своем собственном дереве.
Однако, если вы используете выражение типа:
/descendant::input[@type='text'][1]
или
/descendant::input[@type='text'][2]
первое выражение возьмет первый вход, а второе - второй. Очень важно, чтобы вы использовали одинарный "/", а НЕ двойной "//".
С помощью
/descendant::input[@type='text'][1]
/descendant::input[@type='text'][2]
вы можете искать только все входные элементы в дереве. Это не сработает, если вы просто хотите проанализировать поддерево.
Лучший способ:
(/form/div/input[@type='text'])[1]
(/form/div/input[@type='text'])[2]
, который вернет результат # 1, # 2 и т. Д. Выражения XPath в скобках.
Конечно, вы также можете сделать
(//input[@type='text'])[1]
Это очень удобно, поскольку Selenium просто использует первое совпадение и не может работать с набором результатов, что обычно возвращает XPath.